mirror of https://github.com/oxen-io/oxen-core.git
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:
parent
601e9f77e1
commit
a62ff316e3
|
@ -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>();
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -33,8 +33,6 @@ extern "C"
|
|||
namespace lns
|
||||
{
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
enum struct lns_sql_type
|
||||
{
|
||||
save_owner,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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 = {};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -61,7 +61,6 @@ DISABLE_VS_WARNINGS(4355)
|
|||
|
||||
namespace nodetool
|
||||
{
|
||||
using namespace std::literals;
|
||||
struct proxy
|
||||
{
|
||||
proxy()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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"};
|
||||
|
|
Loading…
Reference in New Issue