Merge pull request #1422 from jagerman/uptime-proof-tweaks

Tweak uptime proof times; reduce times for testnet
This commit is contained in:
Jason Rhinelander 2021-03-25 20:57:55 -03:00 committed by GitHub
commit d164e1a41e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 121 additions and 87 deletions

View file

@ -897,11 +897,6 @@ if(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND ARCH_WIDTH EQUAL "32" AND NOT IOS AN
endif()
endif()
option(OXEN_DEBUG_SHORT_PROOFS "Developer option to substantially reduce uptime proof intervals for local test network debugging (the result oxend will not be usable on the live networks)" OFF)
if (OXEN_DEBUG_SHORT_PROOFS)
add_definitions(-DUPTIME_PROOF_BASE_MINUTE=3) # 20x faster uptime proofs
endif()
if(BUILD_STATIC_DEPS)
# sqlite3 target already set up

View file

@ -29,9 +29,6 @@
#ifndef OXEN_H
#define OXEN_H
#define OXEN_HOUR(val) ((val) * OXEN_MINUTES(60))
#define OXEN_MINUTES(val) val * 60
#include <cstddef>
#include <utility>

View file

@ -61,20 +61,6 @@ static_assert(STAKING_PORTIONS % 12 == 0, "Use a multiple of twelve, so that it
#define BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW 11
// For local testnet debug purposes allow shrinking the uptime proof frequency
#ifndef UPTIME_PROOF_BASE_MINUTE
#define UPTIME_PROOF_BASE_MINUTE 60
#endif
#define UPTIME_PROOF_BUFFER_IN_SECONDS (5*60) // The acceptable window of time to accept a peer's uptime proof from its reported timestamp
#define UPTIME_PROOF_INITIAL_DELAY_SECONDS (2*UPTIME_PROOF_BASE_MINUTE) // Delay after startup before sending a proof (to allow connections to be established)
#define UPTIME_PROOF_TIMER_SECONDS (5*UPTIME_PROOF_BASE_MINUTE) // How often we check whether we need to send an uptime proof
#define UPTIME_PROOF_FREQUENCY_IN_SECONDS (60*UPTIME_PROOF_BASE_MINUTE) // How often we resend uptime proofs normally (i.e. after we've seen an uptime proof reply from the network)
#define UPTIME_PROOF_MAX_TIME_IN_SECONDS (UPTIME_PROOF_FREQUENCY_IN_SECONDS * 2 + UPTIME_PROOF_BUFFER_IN_SECONDS) // How long until proofs of other network service nodes are considered expired
#define STORAGE_SERVER_PING_LIFETIME UPTIME_PROOF_FREQUENCY_IN_SECONDS
#define LOKINET_PING_LIFETIME UPTIME_PROOF_FREQUENCY_IN_SECONDS
#define CRYPTONOTE_REWARD_BLOCKS_WINDOW 100
#define CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1 20000 // NOTE(oxen): For testing suite, //size of block (bytes) after which reward for block calculated using block size - before first fork
#define CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 300000 //size of block (bytes) after which reward for block calculated using block size - second change, from v5
@ -250,6 +236,12 @@ namespace config
"LDBEN6Ut4NkMwyaXWZ7kBEAx8X64o6YtDhLXUP26uLHyYT4nFmcaPU2Z2fauqrhTLh4Qfr61pUUZVLaTHqAdycETKM1STrz"sv, // hardfork v11
};
inline constexpr auto UPTIME_PROOF_TOLERANCE = 5min; // How much an uptime proof timestamp can deviate from our timestamp before we refuse it
inline constexpr auto UPTIME_PROOF_STARTUP_DELAY = 30s; // How long to wait after startup before broadcasting a proof
inline constexpr auto UPTIME_PROOF_CHECK_INTERVAL = 30s; // How frequently to check whether we need to broadcast a proof
inline constexpr auto UPTIME_PROOF_FREQUENCY = 1h; // How often to send proofs out to the network since the last proof we successfully sent. (Approximately; this can be up to CHECK_INTERFACE/2 off in either direction). The minimum accepted time between proofs is half of this.
inline constexpr auto UPTIME_PROOF_VALIDITY = 2h + 5min; // The maximum time that we consider an uptime proof to be valid (i.e. after this time since the last proof we consider the SN to be down)
// Hash domain separators
inline constexpr std::string_view HASH_KEY_BULLETPROOF_EXPONENT = "bulletproof"sv;
inline constexpr std::string_view HASH_KEY_RINGDB = "ringdsb\0"sv;
@ -288,6 +280,9 @@ namespace config
"T6TzkJb5EiASaCkcH7idBEi1HSrpSQJE1Zq3aL65ojBMPZvqHNYPTL56i3dncGVNEYCG5QG5zrBmRiVwcg6b1cRM1SRNqbp44"sv, // hardfork v10
};
// Testnet uptime proofs are 6x faster than mainnet (devnet config also uses these)
inline constexpr auto UPTIME_PROOF_FREQUENCY = 10min;
inline constexpr auto UPTIME_PROOF_VALIDITY = 21min;
}
namespace devnet
@ -314,6 +309,15 @@ namespace config
"dV3EhSE1xXgSzswBgVioqFNTfcqGopvTrcYjs4YDLHUfU64DuHxFoEmbwoyipTidGiTXx5EuYdgzZhDLMTo9uEv82M4A7Uimp"sv, // hardfork v10
};
}
namespace fakechain {
// Fakechain uptime proofs are 60x faster than mainnet, because this really only runs on a
// hand-crafted, typically local temporary network.
inline constexpr auto UPTIME_PROOF_STARTUP_DELAY = 5s;
inline constexpr auto UPTIME_PROOF_CHECK_INTERVAL = 5s;
inline constexpr auto UPTIME_PROOF_FREQUENCY = 1min;
inline constexpr auto UPTIME_PROOF_VALIDITY = 2min + 5s;
}
}
namespace cryptonote
@ -376,6 +380,12 @@ namespace cryptonote
uint64_t GOVERNANCE_REWARD_INTERVAL_IN_BLOCKS;
std::array<std::string_view, 2> GOVERNANCE_WALLET_ADDRESS;
std::chrono::seconds UPTIME_PROOF_TOLERANCE;
std::chrono::seconds UPTIME_PROOF_STARTUP_DELAY;
std::chrono::seconds UPTIME_PROOF_CHECK_INTERVAL;
std::chrono::seconds UPTIME_PROOF_FREQUENCY;
std::chrono::seconds UPTIME_PROOF_VALIDITY;
inline constexpr std::string_view governance_wallet_address(int hard_fork_version) const {
const auto wallet_switch =
(NETWORK_TYPE == MAINNET || NETWORK_TYPE == FAKECHAIN)
@ -384,7 +394,7 @@ namespace cryptonote
return GOVERNANCE_WALLET_ADDRESS[hard_fork_version >= wallet_switch ? 1 : 0];
}
};
inline constexpr network_config mainnet_config = {
inline constexpr network_config mainnet_config{
MAINNET,
::config::HEIGHT_ESTIMATE_HEIGHT,
::config::HEIGHT_ESTIMATE_TIMESTAMP,
@ -400,8 +410,13 @@ namespace cryptonote
::config::GENESIS_NONCE,
::config::GOVERNANCE_REWARD_INTERVAL_IN_BLOCKS,
::config::GOVERNANCE_WALLET_ADDRESS,
config::UPTIME_PROOF_TOLERANCE,
config::UPTIME_PROOF_STARTUP_DELAY,
config::UPTIME_PROOF_CHECK_INTERVAL,
config::UPTIME_PROOF_FREQUENCY,
config::UPTIME_PROOF_VALIDITY,
};
inline constexpr network_config testnet_config = {
inline constexpr network_config testnet_config{
TESTNET,
::config::testnet::HEIGHT_ESTIMATE_HEIGHT,
::config::testnet::HEIGHT_ESTIMATE_TIMESTAMP,
@ -417,8 +432,13 @@ namespace cryptonote
::config::testnet::GENESIS_NONCE,
::config::testnet::GOVERNANCE_REWARD_INTERVAL_IN_BLOCKS,
::config::testnet::GOVERNANCE_WALLET_ADDRESS,
config::UPTIME_PROOF_TOLERANCE,
config::UPTIME_PROOF_STARTUP_DELAY,
config::UPTIME_PROOF_CHECK_INTERVAL,
config::testnet::UPTIME_PROOF_FREQUENCY,
config::testnet::UPTIME_PROOF_VALIDITY,
};
inline constexpr network_config devnet_config = {
inline constexpr network_config devnet_config{
DEVNET,
::config::devnet::HEIGHT_ESTIMATE_HEIGHT,
::config::devnet::HEIGHT_ESTIMATE_TIMESTAMP,
@ -434,8 +454,13 @@ namespace cryptonote
::config::devnet::GENESIS_NONCE,
::config::devnet::GOVERNANCE_REWARD_INTERVAL_IN_BLOCKS,
::config::devnet::GOVERNANCE_WALLET_ADDRESS,
config::UPTIME_PROOF_TOLERANCE,
config::UPTIME_PROOF_STARTUP_DELAY,
config::UPTIME_PROOF_CHECK_INTERVAL,
config::testnet::UPTIME_PROOF_FREQUENCY,
config::testnet::UPTIME_PROOF_VALIDITY,
};
inline constexpr network_config fakenet_config = {
inline constexpr network_config fakenet_config{
FAKECHAIN,
::config::HEIGHT_ESTIMATE_HEIGHT,
::config::HEIGHT_ESTIMATE_TIMESTAMP,
@ -451,6 +476,11 @@ namespace cryptonote
::config::GENESIS_NONCE,
100, //::config::GOVERNANCE_REWARD_INTERVAL_IN_BLOCKS,
::config::GOVERNANCE_WALLET_ADDRESS,
config::UPTIME_PROOF_TOLERANCE,
config::fakechain::UPTIME_PROOF_STARTUP_DELAY,
config::fakechain::UPTIME_PROOF_CHECK_INTERVAL,
config::fakechain::UPTIME_PROOF_FREQUENCY,
config::fakechain::UPTIME_PROOF_VALIDITY,
};
inline constexpr const network_config& get_config(network_type nettype)

View file

@ -376,6 +376,7 @@ namespace cryptonote
const bool devnet = command_line::get_arg(vm, arg_devnet_on);
m_nettype = testnet ? TESTNET : devnet ? DEVNET : MAINNET;
}
m_check_uptime_proof_interval.interval(get_net_config().UPTIME_PROOF_CHECK_INTERVAL);
m_config_folder = fs::u8path(command_line::get_arg(vm, arg_data_dir));
@ -2276,14 +2277,14 @@ namespace cryptonote
return m_blockchain_storage.get_block_by_height(height, blk);
}
//-----------------------------------------------------------------------------------------------
static bool check_external_ping(time_t last_ping, time_t lifetime, const char *what)
static bool check_external_ping(time_t last_ping, std::chrono::seconds lifetime, std::string_view what)
{
const auto elapsed = std::time(nullptr) - last_ping;
const std::chrono::seconds elapsed{std::time(nullptr) - last_ping};
if (elapsed > lifetime)
{
MWARNING("Have not heard from " << what << " " <<
(!last_ping ? "since starting" :
"for more than " + tools::get_human_readable_timespan(std::chrono::seconds(elapsed))));
"since more than " + tools::get_human_readable_timespan(elapsed) + " ago"));
return false;
}
return true;
@ -2303,10 +2304,12 @@ namespace cryptonote
m_check_uptime_proof_interval.do_call([this]() {
// This timer is not perfectly precise and can leak seconds slightly, so send the uptime
// proof if we are within half a tick of the target time. (Essentially our target proof
// window becomes the first time this triggers in the 57.5-62.5 minute window).
// window becomes the first time this triggers in the 59.75-60.25 minute window).
uint64_t next_proof_time = 0;
m_service_node_list.access_proof(m_service_keys.pub, [&](auto &proof) { next_proof_time = proof.timestamp; });
next_proof_time += UPTIME_PROOF_FREQUENCY_IN_SECONDS - UPTIME_PROOF_TIMER_SECONDS/2;
auto& netconf = get_net_config();
next_proof_time += std::chrono::seconds{
netconf.UPTIME_PROOF_FREQUENCY - netconf.UPTIME_PROOF_CHECK_INTERVAL/2}.count();
if ((uint64_t) std::time(nullptr) < next_proof_time)
return;
@ -2341,14 +2344,14 @@ namespace cryptonote
if (m_nettype != DEVNET)
{
if (!check_external_ping(m_last_storage_server_ping, STORAGE_SERVER_PING_LIFETIME, "the storage server"))
if (!check_external_ping(m_last_storage_server_ping, get_net_config().UPTIME_PROOF_FREQUENCY, "the storage server"))
{
MGINFO_RED(
"Failed to submit uptime proof: have not heard from the storage server recently. Make sure that it "
"is running! It is required to run alongside the Loki daemon");
return;
}
if (!check_external_ping(m_last_lokinet_ping, LOKINET_PING_LIFETIME, "Lokinet"))
if (!check_external_ping(m_last_lokinet_ping, get_net_config().UPTIME_PROOF_FREQUENCY, "Lokinet"))
{
MGINFO_RED(
"Failed to submit uptime proof: have not heard from lokinet recently. Make sure that it "
@ -2395,9 +2398,8 @@ namespace cryptonote
m_block_rate_interval.do_call([this] { return check_block_rate(); });
m_sn_proof_cleanup_interval.do_call([&snl=m_service_node_list] { snl.cleanup_proofs(); return true; });
time_t const lifetime = time(nullptr) - get_start_time();
int proof_delay = m_nettype == FAKECHAIN ? 5 : UPTIME_PROOF_INITIAL_DELAY_SECONDS;
if (m_service_node && lifetime > proof_delay) // Give us some time to connect to peers before sending uptimes
std::chrono::seconds lifetime{time(nullptr) - get_start_time()};
if (m_service_node && lifetime > get_net_config().UPTIME_PROOF_STARTUP_DELAY) // Give us some time to connect to peers before sending uptimes
{
do_uptime_proof_call();
}

View file

@ -851,6 +851,11 @@ namespace cryptonote
*/
network_type get_nettype() const { return m_nettype; };
/**
* Returns the config settings for the network we are on.
*/
constexpr const network_config& get_net_config() const { return get_config(m_nettype); }
/**
* @brief get whether transaction relay should be padded
*
@ -1218,7 +1223,7 @@ namespace cryptonote
tools::periodic_task m_fork_moaner{2h}; //!< interval for checking HardFork status
tools::periodic_task m_txpool_auto_relayer{2min, false}; //!< interval for checking re-relaying txpool transactions
tools::periodic_task m_check_disk_space_interval{10min}; //!< interval for checking for disk space
tools::periodic_task m_check_uptime_proof_interval{std::chrono::seconds{UPTIME_PROOF_TIMER_SECONDS}}; //!< interval for checking our own uptime proof
tools::periodic_task m_check_uptime_proof_interval{30s}; //!< interval for checking our own uptime proof (will be set to get_net_config().UPTIME_PROOF_CHECK_INTERVAL after init)
tools::periodic_task m_block_rate_interval{90s, false}; //!< interval for checking block rate
tools::periodic_task m_blockchain_pruning_interval{5h}; //!< interval for incremental blockchain pruning
tools::periodic_task m_service_node_vote_relayer{2min, false};

View file

@ -69,9 +69,9 @@ namespace service_nodes
{
size_t constexpr STORE_LONG_TERM_STATE_INTERVAL = 10000;
constexpr int X25519_MAP_PRUNING_INTERVAL = 5*60;
constexpr int X25519_MAP_PRUNING_LAG = 24*60*60;
static_assert(X25519_MAP_PRUNING_LAG > UPTIME_PROOF_MAX_TIME_IN_SECONDS, "x25519 map pruning lag is too short!");
constexpr auto X25519_MAP_PRUNING_INTERVAL = 5min;
constexpr auto X25519_MAP_PRUNING_LAG = 24h;
static_assert(X25519_MAP_PRUNING_LAG > config::UPTIME_PROOF_VALIDITY, "x25519 map pruning lag is too short!");
static uint64_t short_term_state_cull_height(uint8_t hf_version, uint64_t block_height)
{
@ -2906,10 +2906,12 @@ namespace service_nodes
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);
auto& netconf = get_config(m_blockchain.nettype());
auto now = std::chrono::system_clock::now();
// Validate proof version, timestamp range,
if ((proof.timestamp < now - UPTIME_PROOF_BUFFER_IN_SECONDS) || (proof.timestamp > now + UPTIME_PROOF_BUFFER_IN_SECONDS))
auto time_deviation = now - std::chrono::system_clock::from_time_t(proof.timestamp);
if (time_deviation > netconf.UPTIME_PROOF_TOLERANCE || time_deviation < -netconf.UPTIME_PROOF_TOLERANCE)
REJECT_PROOF("timestamp is too far from now");
for (auto const &min : MIN_UPTIME_PROOF_VERSIONS)
@ -2950,7 +2952,7 @@ namespace service_nodes
auto &iproof = proofs[proof.pubkey];
if (iproof.timestamp >= now - (UPTIME_PROOF_FREQUENCY_IN_SECONDS / 2))
if (now <= std::chrono::system_clock::from_time_t(iproof.timestamp) + std::chrono::seconds{netconf.UPTIME_PROOF_FREQUENCY} / 2)
REJECT_PROOF("already received one uptime proof for this node recently");
if (m_service_node_keys && proof.pubkey == m_service_node_keys->pub)
@ -2969,13 +2971,13 @@ namespace service_nodes
}
auto old_x25519 = iproof.pubkey_x25519;
if (iproof.update(now, proof.public_ip, proof.storage_port, proof.storage_lmq_port, proof.qnet_port, proof.snode_version, proof.pubkey_ed25519, derived_x25519_pubkey))
if (iproof.update(std::chrono::system_clock::to_time_t(now), proof.public_ip, proof.storage_port, proof.storage_lmq_port, proof.qnet_port, proof.snode_version, proof.pubkey_ed25519, derived_x25519_pubkey))
iproof.store(proof.pubkey, m_blockchain);
if ((uint64_t) x25519_map_last_pruned + X25519_MAP_PRUNING_INTERVAL <= now)
if (now - x25519_map_last_pruned >= X25519_MAP_PRUNING_INTERVAL)
{
time_t cutoff = now - X25519_MAP_PRUNING_LAG;
erase_if(x25519_to_pub, [&cutoff](const decltype(x25519_to_pub)::value_type &x) { return x.second.second < cutoff; });
time_t cutoff = std::chrono::system_clock::to_time_t(now - X25519_MAP_PRUNING_LAG);
erase_if(x25519_to_pub, [&cutoff](auto &x) { return x.second.second < cutoff; });
x25519_map_last_pruned = now;
}
@ -2983,7 +2985,7 @@ namespace service_nodes
x25519_to_pub.erase(old_x25519);
if (derived_x25519_pubkey)
x25519_to_pub[derived_x25519_pubkey] = {proof.pubkey, now};
x25519_to_pub[derived_x25519_pubkey] = {proof.pubkey, std::chrono::system_clock::to_time_t(now)};
if (derived_x25519_pubkey && (old_x25519 != derived_x25519_pubkey))
x25519_pkey = derived_x25519_pubkey;
@ -2997,10 +2999,12 @@ namespace service_nodes
bool service_node_list::handle_btencoded_uptime_proof(std::unique_ptr<uptime_proof::Proof> 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);
auto& netconf = get_config(m_blockchain.nettype());
auto now = std::chrono::system_clock::now();
// Validate proof version, timestamp range,
if ((proof->timestamp < now - UPTIME_PROOF_BUFFER_IN_SECONDS) || (proof->timestamp > now + UPTIME_PROOF_BUFFER_IN_SECONDS))
auto time_deviation = now - std::chrono::system_clock::from_time_t(proof->timestamp);
if (time_deviation > netconf.UPTIME_PROOF_TOLERANCE || time_deviation < -netconf.UPTIME_PROOF_TOLERANCE)
REJECT_PROOF("timestamp is too far from now");
for (auto const &min : MIN_UPTIME_PROOF_VERSIONS)
@ -3039,7 +3043,7 @@ namespace service_nodes
auto &iproof = proofs[proof->pubkey];
if (iproof.timestamp >= now - (UPTIME_PROOF_FREQUENCY_IN_SECONDS / 2))
if (now <= std::chrono::system_clock::from_time_t(iproof.timestamp) + std::chrono::seconds{netconf.UPTIME_PROOF_FREQUENCY} / 2)
REJECT_PROOF("already received one uptime proof for this node recently");
if (m_service_node_keys && proof->pubkey == m_service_node_keys->pub)
@ -3058,14 +3062,14 @@ namespace service_nodes
}
auto old_x25519 = iproof.pubkey_x25519;
if (iproof.update(now, std::move(proof), derived_x25519_pubkey))
if (iproof.update(std::chrono::system_clock::to_time_t(now), std::move(proof), derived_x25519_pubkey))
{
iproof.store(iproof.proof->pubkey, m_blockchain);
}
if ((uint64_t) x25519_map_last_pruned + X25519_MAP_PRUNING_INTERVAL <= now)
if (now - x25519_map_last_pruned >= X25519_MAP_PRUNING_INTERVAL)
{
time_t cutoff = now - X25519_MAP_PRUNING_LAG;
time_t cutoff = std::chrono::system_clock::to_time_t(now - X25519_MAP_PRUNING_LAG);
erase_if(x25519_to_pub, [&cutoff](const decltype(x25519_to_pub)::value_type &x) { return x.second.second < cutoff; });
x25519_map_last_pruned = now;
}
@ -3074,7 +3078,7 @@ namespace service_nodes
x25519_to_pub.erase(old_x25519);
if (derived_x25519_pubkey)
x25519_to_pub[derived_x25519_pubkey] = {iproof.proof->pubkey, now};
x25519_to_pub[derived_x25519_pubkey] = {iproof.proof->pubkey, std::chrono::system_clock::to_time_t(now)};
if (derived_x25519_pubkey && (old_x25519 != derived_x25519_pubkey))
x25519_pkey = derived_x25519_pubkey;

View file

@ -672,7 +672,7 @@ namespace service_nodes
/// Maps x25519 pubkeys to registration pubkeys + last block seen value (used for expiry)
std::unordered_map<crypto::x25519_public_key, std::pair<crypto::public_key, time_t>> x25519_to_pub;
time_t x25519_map_last_pruned = 0;
std::chrono::system_clock::time_point x25519_map_last_pruned = std::chrono::system_clock::from_time_t(0);
std::unordered_map<crypto::public_key, proof_info> proofs;
struct quorums_by_height

View file

@ -84,6 +84,8 @@ namespace service_nodes
// has submitted uptime proofs, participated in required quorums, etc.
service_node_test_results quorum_cop::check_service_node(uint8_t hf_version, const crypto::public_key &pubkey, const service_node_info &info) const
{
const auto& netconf = m_core.get_net_config();
service_node_test_results result; // Defaults to true for individual tests
bool ss_reachable = true;
uint64_t timestamp = 0;
@ -112,7 +114,7 @@ namespace service_nodes
}
});
uint64_t time_since_last_uptime_proof = std::time(nullptr) - timestamp;
std::chrono::seconds time_since_last_uptime_proof{std::time(nullptr) - timestamp};
bool check_uptime_obligation = true;
bool check_checkpoint_obligation = true;
@ -122,12 +124,12 @@ namespace service_nodes
if (integration_test::state.disable_obligation_checkpointing) check_checkpoint_obligation = false;
#endif
if (check_uptime_obligation && time_since_last_uptime_proof > UPTIME_PROOF_MAX_TIME_IN_SECONDS)
if (check_uptime_obligation && time_since_last_uptime_proof > netconf.UPTIME_PROOF_VALIDITY)
{
LOG_PRINT_L1(
"Service Node: " << pubkey << ", failed uptime proof obligation check: the last uptime proof was older than: "
<< UPTIME_PROOF_MAX_TIME_IN_SECONDS << "s. Time since last uptime proof was: "
<< tools::get_human_readable_timespan(std::chrono::seconds(time_since_last_uptime_proof)));
"Service Node: " << pubkey << ", failed uptime proof obligation check: the last uptime proof (" <<
tools::get_human_readable_timespan(time_since_last_uptime_proof) << ") was older than max validity (" <<
tools::get_human_readable_timespan(netconf.UPTIME_PROOF_VALIDITY) << ")");
result.uptime_proved = false;
}
@ -145,8 +147,8 @@ namespace service_nodes
std::vector<cryptonote::block> blocks;
if (m_core.get_blocks(info.last_ip_change_height, 1, blocks)) {
uint64_t find_ips_used_since = std::max(
uint64_t(std::time(nullptr)) - IP_CHANGE_WINDOW_IN_SECONDS,
uint64_t(blocks[0].timestamp) + IP_CHANGE_BUFFER_IN_SECONDS);
uint64_t(std::time(nullptr)) - std::chrono::seconds{IP_CHANGE_WINDOW}.count(),
uint64_t(blocks[0].timestamp) + std::chrono::seconds{IP_CHANGE_BUFFER}.count());
if (ips[0].second > find_ips_used_since && ips[1].second > find_ips_used_since)
result.single_ip = false;
}
@ -242,6 +244,8 @@ namespace service_nodes
if (hf_version < cryptonote::network_version_9_service_nodes)
return;
const auto& netconf = m_core.get_net_config();
uint64_t const REORG_SAFETY_BUFFER_BLOCKS = (hf_version >= cryptonote::network_version_12_checkpointing)
? REORG_SAFETY_BUFFER_BLOCKS_POST_HF12
: REORG_SAFETY_BUFFER_BLOCKS_PRE_HF12;
@ -260,9 +264,8 @@ namespace service_nodes
service_nodes::quorum_type const max_quorum_type = service_nodes::max_quorum_type_for_hf(hf_version);
bool tested_myself_once_per_block = false;
time_t start_time = m_core.get_start_time();
time_t const now = time(nullptr);
int const live_time = (now - start_time);
time_t start_time = m_core.get_start_time();
std::chrono::seconds live_time{time(nullptr) - start_time};
for (int i = 0; i <= (int)max_quorum_type; i++)
{
quorum_type const type = static_cast<quorum_type>(i);
@ -317,22 +320,16 @@ namespace service_nodes
}
}
// NOTE: Wait at least 2 hours before we're allowed to vote so that we collect necessary voting information from people on the network
bool alive_for_min_time = live_time >= MIN_TIME_IN_S_BEFORE_VOTING;
if (!alive_for_min_time)
#ifndef OXEN_ENABLE_INTEGRATION_TEST_HOOKS
// NOTE: Wait at least 2 hours before we're allowed to vote so that we collect necessary
// voting information from people on the network
if (live_time < m_core.get_net_config().UPTIME_PROOF_VALIDITY)
continue;
#endif
if (!m_core.service_node())
continue;
if (m_core.get_nettype() == cryptonote::MAINNET && m_core.get_current_blockchain_height() < 646151)
{
// TODO(oxen): Pulse grace period, temporary code to be deleted
// once the grace height has transpired to give Service Nodes time
// to upgrade for the Pulse sorting key hot fix.
continue;
}
auto quorum = m_core.get_quorum(quorum_type::obligations, m_obligations_height);
if (!quorum)
{
@ -448,8 +445,8 @@ namespace service_nodes
// NOTE: Don't warn uptime proofs if the daemon is just
// recently started and is candidate for testing (i.e.
// restarting the daemon)
if (!my_test_results.uptime_proved && live_time < OXEN_HOUR(1))
continue;
if (!my_test_results.uptime_proved && live_time < 1h)
continue;
LOG_PRINT_L0("Service Node (yours) is active but is not passing tests for quorum: " << m_obligations_height);
LOG_PRINT_L0(my_test_results.why());

View file

@ -156,7 +156,6 @@ namespace service_nodes {
#if defined(OXEN_ENABLE_INTEGRATION_TEST_HOOKS)
constexpr size_t STATE_CHANGE_QUORUM_SIZE = 5;
constexpr size_t STATE_CHANGE_MIN_VOTES_TO_CHANGE_STATE = 1;
constexpr int MIN_TIME_IN_S_BEFORE_VOTING = 0;
constexpr size_t CHECKPOINT_QUORUM_SIZE = 5;
constexpr size_t CHECKPOINT_MIN_VOTES = 1;
constexpr int BLINK_SUBQUORUM_SIZE = 5;
@ -164,7 +163,6 @@ namespace service_nodes {
#else
constexpr size_t STATE_CHANGE_MIN_VOTES_TO_CHANGE_STATE = 7;
constexpr size_t STATE_CHANGE_QUORUM_SIZE = 10;
constexpr int MIN_TIME_IN_S_BEFORE_VOTING = UPTIME_PROOF_MAX_TIME_IN_SECONDS;
constexpr size_t CHECKPOINT_QUORUM_SIZE = 20;
constexpr size_t CHECKPOINT_MIN_VOTES = 13;
constexpr int BLINK_SUBQUORUM_SIZE = 10;
@ -184,8 +182,8 @@ namespace service_nodes {
static_assert(REORG_SAFETY_BUFFER_BLOCKS_POST_HF12 < VOTE_LIFETIME, "Safety buffer should always be less than the vote lifetime");
static_assert(REORG_SAFETY_BUFFER_BLOCKS_PRE_HF12 < VOTE_LIFETIME, "Safety buffer should always be less than the vote lifetime");
constexpr uint64_t IP_CHANGE_WINDOW_IN_SECONDS = 24*60*60; // How far back an obligations quorum looks for multiple IPs (unless the following buffer is more recent)
constexpr uint64_t IP_CHANGE_BUFFER_IN_SECONDS = 2*60*60; // After we bump a SN for an IP change we don't bump again for changes within this time period
constexpr auto IP_CHANGE_WINDOW = 24h; // How far back an obligations quorum looks for multiple IPs (unless the following buffer is more recent)
constexpr auto IP_CHANGE_BUFFER = 2h; // After we bump a SN for an IP change we don't bump again for changes within this time period
constexpr size_t MAX_SWARM_SIZE = 10;
// We never create a new swarm unless there are SWARM_BUFFER extra nodes

View file

@ -3278,7 +3278,13 @@ namespace cryptonote { namespace rpc {
// argument: true if this ping should trigger an immediate proof send (i.e. first ping after
// startup or after a ping expiry), false for an ordinary ping.
template <typename RPC, typename Success>
auto handle_ping(std::array<uint16_t, 3> cur_version, std::array<uint16_t, 3> required, const char* name, std::atomic<std::time_t>& update, time_t lifetime, Success success)
auto handle_ping(
std::array<uint16_t, 3> cur_version,
std::array<uint16_t, 3> required,
std::string_view name,
std::atomic<std::time_t>& update,
std::chrono::seconds lifetime,
Success success)
{
typename RPC::response res{};
if (cur_version < required) {
@ -3289,7 +3295,7 @@ namespace cryptonote { namespace rpc {
} else {
auto now = std::time(nullptr);
auto old = update.exchange(now);
bool significant = old + lifetime < now; // Print loudly for the first ping after startup/expiry
bool significant = std::chrono::seconds{now - old} > lifetime; // Print loudly for the first ping after startup/expiry
if (significant)
MGINFO_GREEN("Received ping from " << name << " " << version_printer{cur_version});
else
@ -3307,7 +3313,7 @@ namespace cryptonote { namespace rpc {
m_core.ss_version = {req.version_major, req.version_minor, req.version_patch};
return handle_ping<STORAGE_SERVER_PING>(
{req.version_major, req.version_minor, req.version_patch}, service_nodes::MIN_STORAGE_SERVER_VERSION,
"Storage Server", m_core.m_last_storage_server_ping, STORAGE_SERVER_PING_LIFETIME,
"Storage Server", m_core.m_last_storage_server_ping, m_core.get_net_config().UPTIME_PROOF_FREQUENCY,
[this, &req](bool significant) {
m_core.m_storage_lmq_port = req.storage_lmq_port;
if (significant)
@ -3320,7 +3326,7 @@ namespace cryptonote { namespace rpc {
m_core.lokinet_version = req.version;
return handle_ping<LOKINET_PING>(
req.version, service_nodes::MIN_LOKINET_VERSION,
"Lokinet", m_core.m_last_lokinet_ping, LOKINET_PING_LIFETIME,
"Lokinet", m_core.m_last_lokinet_ping, m_core.get_net_config().UPTIME_PROOF_FREQUENCY,
[this](bool significant) { if (significant) m_core.reset_proof_interval(); });
}
//------------------------------------------------------------------------------------------------------------------------------