Support dynamic PPLNS window in status

hardfork
SChernykh 1 year ago
parent 578baeae96
commit 14f667de74

@ -56,6 +56,7 @@ public:
bool submit_sidechain_block(uint32_t template_id, uint32_t nonce, uint32_t extra_nonce); bool submit_sidechain_block(uint32_t template_id, uint32_t nonce, uint32_t extra_nonce);
FORCEINLINE const std::vector<MinerShare>& shares() const { return m_shares; } FORCEINLINE const std::vector<MinerShare>& shares() const { return m_shares; }
FORCEINLINE uint64_t get_reward() const { return m_finalReward; }
#ifdef P2POOL_UNIT_TESTS #ifdef P2POOL_UNIT_TESTS
FORCEINLINE const PoolBlock* pool_block_template() const { return m_poolBlockTemplate; } FORCEINLINE const PoolBlock* pool_block_template() const { return m_poolBlockTemplate; }

@ -327,7 +327,7 @@ P2PServer* SideChain::p2pServer() const
return m_pool ? m_pool->p2p_server() : nullptr; return m_pool ? m_pool->p2p_server() : nullptr;
} }
bool SideChain::get_shares(const PoolBlock* tip, std::vector<MinerShare>& shares, bool quiet) const bool SideChain::get_shares(const PoolBlock* tip, std::vector<MinerShare>& shares, uint64_t* bottom_height, bool quiet) const
{ {
if (tip->m_txkeySecSeed.empty()) { if (tip->m_txkeySecSeed.empty()) {
LOGERR(1, "tx key seed is not set, fix the code!"); LOGERR(1, "tx key seed is not set, fix the code!");
@ -432,6 +432,10 @@ bool SideChain::get_shares(const PoolBlock* tip, std::vector<MinerShare>& shares
cur = it->second; cur = it->second;
} while (true); } while (true);
if (bottom_height) {
*bottom_height = cur->m_sidechainHeight;
}
shares.assign(shares_set.begin(), shares_set.end()); shares.assign(shares_set.begin(), shares_set.end());
std::sort(shares.begin(), shares.end(), [](const auto& a, const auto& b) { return *a.m_wallet < *b.m_wallet; }); std::sort(shares.begin(), shares.end(), [](const auto& a, const auto& b) { return *a.m_wallet < *b.m_wallet; });
@ -878,7 +882,7 @@ bool SideChain::get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::v
void SideChain::print_status(bool obtain_sidechain_lock) const void SideChain::print_status(bool obtain_sidechain_lock) const
{ {
std::vector<hash> blocks_in_window; unordered_set<hash> blocks_in_window;
blocks_in_window.reserve(m_chainWindowSize * 9 / 8); blocks_in_window.reserve(m_chainWindowSize * 9 / 8);
const difficulty_type diff = difficulty(); const difficulty_type diff = difficulty();
@ -886,51 +890,58 @@ void SideChain::print_status(bool obtain_sidechain_lock) const
if (obtain_sidechain_lock) uv_rwlock_rdlock(&m_sidechainLock); if (obtain_sidechain_lock) uv_rwlock_rdlock(&m_sidechainLock);
ON_SCOPE_LEAVE([this, obtain_sidechain_lock]() { if (obtain_sidechain_lock) uv_rwlock_rdunlock(&m_sidechainLock); }); ON_SCOPE_LEAVE([this, obtain_sidechain_lock]() { if (obtain_sidechain_lock) uv_rwlock_rdunlock(&m_sidechainLock); });
uint64_t rem; const uint64_t pool_hashrate = (diff / m_targetBlockTime).lo;
uint64_t pool_hashrate = udiv128(diff.hi, diff.lo, m_targetBlockTime, &rem);
difficulty_type network_diff = m_pool->miner_data().difficulty; const difficulty_type network_diff = m_pool->miner_data().difficulty;
uint64_t network_hashrate = udiv128(network_diff.hi, network_diff.lo, MONERO_BLOCK_TIME, &rem); const uint64_t network_hashrate = (network_diff / MONERO_BLOCK_TIME).lo;
const PoolBlock* tip = m_chainTip; const PoolBlock* tip = m_chainTip;
std::vector<MinerShare> shares;
uint64_t bottom_height = 0;
get_shares(tip, shares, &bottom_height, true);
const uint64_t window_size = bottom_height ? (tip->m_sidechainHeight - bottom_height + 1U) : m_chainWindowSize;
uint64_t block_depth = 0; uint64_t block_depth = 0;
const PoolBlock* cur = tip; const PoolBlock* cur = tip;
const uint64_t tip_height = tip ? tip->m_sidechainHeight : 0; const uint64_t tip_height = tip ? tip->m_sidechainHeight : 0;
uint32_t total_blocks_in_window = 0; uint64_t total_blocks_in_window = 0;
uint32_t total_uncles_in_window = 0; uint64_t total_uncles_in_window = 0;
// each dot corresponds to window_size / 30 shares, with current values, 2160 / 30 = 72
std::array<uint64_t, 30> our_blocks_in_window{};
std::array<uint64_t, 30> our_uncles_in_window{};
// each dot corresponds to m_chainWindowSize / 30 shares, with current values, 2160 / 30 = 72 const Wallet& w = m_pool->params().m_wallet;
std::array<uint32_t, 30> our_blocks_in_window{};
std::array<uint32_t, 30> our_uncles_in_window{};
while (cur) { while (cur) {
blocks_in_window.emplace_back(cur->m_sidechainId); blocks_in_window.emplace(cur->m_sidechainId);
++total_blocks_in_window; ++total_blocks_in_window;
if (cur->m_minerWallet == m_pool->params().m_wallet) { if (cur->m_minerWallet == w) {
// this produces an integer division with quotient rounded up, avoids non-whole divisions from overflowing on total_blocks_in_window // this produces an integer division with quotient rounded up, avoids non-whole divisions from overflowing on total_blocks_in_window
const size_t window_index = (total_blocks_in_window - 1) / ((m_chainWindowSize + our_blocks_in_window.size() - 1) / our_blocks_in_window.size()); const size_t window_index = (total_blocks_in_window - 1) / ((window_size + our_blocks_in_window.size() - 1) / our_blocks_in_window.size());
our_blocks_in_window[std::min(window_index, our_blocks_in_window.size() - 1)]++; // clamp window_index, even if total_blocks_in_window is not larger than m_chainWindowSize our_blocks_in_window[std::min(window_index, our_blocks_in_window.size() - 1)]++; // clamp window_index, even if total_blocks_in_window is not larger than window_size
} }
++block_depth; ++block_depth;
if (block_depth >= m_chainWindowSize) { if (block_depth >= window_size) {
break; break;
} }
for (const hash& uncle_id : cur->m_uncles) { for (const hash& uncle_id : cur->m_uncles) {
blocks_in_window.emplace_back(uncle_id); blocks_in_window.emplace(uncle_id);
auto it = m_blocksById.find(uncle_id); auto it = m_blocksById.find(uncle_id);
if (it != m_blocksById.end()) { if (it != m_blocksById.end()) {
PoolBlock* uncle = it->second; PoolBlock* uncle = it->second;
if (tip_height - uncle->m_sidechainHeight < m_chainWindowSize) { if (tip_height - uncle->m_sidechainHeight < window_size) {
++total_uncles_in_window; ++total_uncles_in_window;
if (uncle->m_minerWallet == m_pool->params().m_wallet) { if (uncle->m_minerWallet == w) {
// this produces an integer division with quotient rounded up, avoids non-whole divisions from overflowing on total_blocks_in_window // this produces an integer division with quotient rounded up, avoids non-whole divisions from overflowing on total_blocks_in_window
const size_t window_index = (total_blocks_in_window - 1) / ((m_chainWindowSize + our_uncles_in_window.size() - 1) / our_uncles_in_window.size()); const size_t window_index = (total_blocks_in_window - 1) / ((window_size + our_uncles_in_window.size() - 1) / our_uncles_in_window.size());
our_uncles_in_window[std::min(window_index, our_uncles_in_window.size() - 1)]++; // clamp window_index, even if total_blocks_in_window is not larger than m_chainWindowSize our_uncles_in_window[std::min(window_index, our_uncles_in_window.size() - 1)]++; // clamp window_index, even if total_blocks_in_window is not larger than window_size
} }
} }
} }
@ -942,65 +953,50 @@ void SideChain::print_status(bool obtain_sidechain_lock) const
uint64_t total_orphans = 0; uint64_t total_orphans = 0;
uint64_t our_orphans = 0; uint64_t our_orphans = 0;
uint64_t your_reward = 0;
uint64_t total_reward = 0;
if (tip) { if (tip) {
std::sort(blocks_in_window.begin(), blocks_in_window.end()); for (uint64_t i = 0; (i < window_size) && (i <= tip_height); ++i) {
for (uint64_t i = 0; (i < m_chainWindowSize) && (i <= tip_height); ++i) {
auto it = m_blocksByHeight.find(tip_height - i); auto it = m_blocksByHeight.find(tip_height - i);
if (it == m_blocksByHeight.end()) { if (it == m_blocksByHeight.end()) {
continue; continue;
} }
for (const PoolBlock* block : it->second) { for (const PoolBlock* block : it->second) {
if (!std::binary_search(blocks_in_window.begin(), blocks_in_window.end(), block->m_sidechainId)) { if (blocks_in_window.find(block->m_sidechainId) == blocks_in_window.end()) {
LOGINFO(4, "orphan block at height " << log::Gray() << block->m_sidechainHeight << log::NoColor() << ": " << log::Gray() << block->m_sidechainId); LOGINFO(4, "orphan block at height " << log::Gray() << block->m_sidechainHeight << log::NoColor() << ": " << log::Gray() << block->m_sidechainId);
++total_orphans; ++total_orphans;
if (block->m_minerWallet == m_pool->params().m_wallet) { if (block->m_minerWallet == w) {
++our_orphans; ++our_orphans;
} }
} }
} }
} }
}
const Wallet& w = m_pool->params().m_wallet; difficulty_type your_shares_weight, pplns_weight;
const uint8_t tx_type = tip->get_tx_type(); for (const MinerShare& s : shares) {
if (*s.m_wallet == w) {
hash eph_public_key; your_shares_weight = s.m_weight;
for (size_t i = 0, n = tip->m_outputs.size(); i < n; ++i) {
const PoolBlock::TxOutput& out = tip->m_outputs[i];
if (!your_reward) {
if (tx_type == TXOUT_TO_TAGGED_KEY) {
uint8_t view_tag;
const uint8_t expected_view_tag = out.m_viewTag;
if (w.get_eph_public_key(tip->m_txkeySec, i, eph_public_key, view_tag, &expected_view_tag) && (out.m_ephPublicKey == eph_public_key)) {
your_reward = out.m_reward;
}
}
else {
uint8_t view_tag;
if (w.get_eph_public_key(tip->m_txkeySec, i, eph_public_key, view_tag) && (out.m_ephPublicKey == eph_public_key)) {
your_reward = out.m_reward;
}
}
}
total_reward += out.m_reward;
} }
pplns_weight += s.m_weight;
} }
uint64_t product[2]; if (pplns_weight == 0) {
product[0] = umul128(pool_hashrate, your_reward, &product[1]); pplns_weight = m_minDifficulty;
const uint64_t hashrate_est = total_reward ? udiv128(product[1], product[0], total_reward, &rem) : 0; }
const uint64_t total_reward = m_pool->block_template().get_reward();
const uint64_t your_reward = ((your_shares_weight * total_reward) / pplns_weight).lo;
const uint64_t hashrate_est = ((your_shares_weight * pool_hashrate) / pplns_weight).lo;
const double block_share = total_reward ? ((static_cast<double>(your_reward) * 100.0) / static_cast<double>(total_reward)) : 0.0; const double block_share = total_reward ? ((static_cast<double>(your_reward) * 100.0) / static_cast<double>(total_reward)) : 0.0;
const uint32_t our_blocks_in_window_total = std::accumulate(our_blocks_in_window.begin(), our_blocks_in_window.end(), 0U); const uint64_t our_blocks_in_window_total = std::accumulate(our_blocks_in_window.begin(), our_blocks_in_window.end(), 0ULL);
const uint32_t our_uncles_in_window_total = std::accumulate(our_uncles_in_window.begin(), our_uncles_in_window.end(), 0U); const uint64_t our_uncles_in_window_total = std::accumulate(our_uncles_in_window.begin(), our_uncles_in_window.end(), 0ULL);
std::string our_blocks_in_window_chart; std::string our_blocks_in_window_chart;
if (our_blocks_in_window_total) { if (our_blocks_in_window_total) {
our_blocks_in_window_chart.reserve(our_blocks_in_window.size() + 32); our_blocks_in_window_chart.reserve(our_blocks_in_window.size() + 32);
our_blocks_in_window_chart = "\nYour shares position = ["; our_blocks_in_window_chart = "\nYour shares position = [";
for (uint32_t p : our_blocks_in_window) { for (uint64_t p : our_blocks_in_window) {
our_blocks_in_window_chart += (p ? ((p > 9) ? '+' : static_cast<char>('0' + p)) : '.'); our_blocks_in_window_chart += (p ? ((p > 9) ? '+' : static_cast<char>('0' + p)) : '.');
} }
our_blocks_in_window_chart += ']'; our_blocks_in_window_chart += ']';
@ -1010,7 +1006,7 @@ void SideChain::print_status(bool obtain_sidechain_lock) const
if (our_uncles_in_window_total) { if (our_uncles_in_window_total) {
our_uncles_in_window_chart.reserve(our_uncles_in_window.size() + 32); our_uncles_in_window_chart.reserve(our_uncles_in_window.size() + 32);
our_uncles_in_window_chart = "\nYour uncles position = ["; our_uncles_in_window_chart = "\nYour uncles position = [";
for (uint32_t p : our_uncles_in_window) { for (uint64_t p : our_uncles_in_window) {
our_uncles_in_window_chart += (p ? ((p > 9) ? '+' : static_cast<char>('0' + p)) : '.'); our_uncles_in_window_chart += (p ? ((p > 9) ? '+' : static_cast<char>('0' + p)) : '.');
} }
our_uncles_in_window_chart += ']'; our_uncles_in_window_chart += ']';
@ -1024,7 +1020,8 @@ void SideChain::print_status(bool obtain_sidechain_lock) const
"\nSide chain hashrate = " << log::Hashrate(pool_hashrate) << "\nSide chain hashrate = " << log::Hashrate(pool_hashrate) <<
(hashrate_est ? "\nYour hashrate (pool-side) = " : "") << (hashrate_est ? log::Hashrate(hashrate_est) : log::Hashrate()) << (hashrate_est ? "\nYour hashrate (pool-side) = " : "") << (hashrate_est ? log::Hashrate(hashrate_est) : log::Hashrate()) <<
"\nPPLNS window = " << total_blocks_in_window << " blocks (+" << total_uncles_in_window << " uncles, " << total_orphans << " orphans)" << "\nPPLNS window = " << total_blocks_in_window << " blocks (+" << total_uncles_in_window << " uncles, " << total_orphans << " orphans)" <<
"\nYour wallet address = " << m_pool->params().m_wallet << "\nPPLNS window duration = " << log::Duration((pplns_weight / pool_hashrate).lo) <<
"\nYour wallet address = " << w <<
"\nYour shares = " << our_blocks_in_window_total << " blocks (+" << our_uncles_in_window_total << " uncles, " << our_orphans << " orphans)" "\nYour shares = " << our_blocks_in_window_total << " blocks (+" << our_uncles_in_window_total << " uncles, " << our_orphans << " orphans)"
<< our_blocks_in_window_chart << our_uncles_in_window_chart << << our_blocks_in_window_chart << our_uncles_in_window_chart <<
"\nBlock reward share = " << block_share << "% (" << log::XMRAmount(your_reward) << ')' "\nBlock reward share = " << block_share << "% (" << log::XMRAmount(your_reward) << ')'
@ -2130,7 +2127,7 @@ void SideChain::launch_precalc(const PoolBlock* block)
continue; continue;
} }
std::vector<MinerShare> shares; std::vector<MinerShare> shares;
if (get_shares(b, shares, true)) { if (get_shares(b, shares, nullptr, true)) {
b->m_precalculated = true; b->m_precalculated = true;
PrecalcJob* job = new PrecalcJob{ b, std::move(shares) }; PrecalcJob* job = new PrecalcJob{ b, std::move(shares) };
{ {

@ -91,7 +91,7 @@ private:
NetworkType m_networkType; NetworkType m_networkType;
private: private:
bool get_shares(const PoolBlock* tip, std::vector<MinerShare>& shares, bool quiet = false) const; bool get_shares(const PoolBlock* tip, std::vector<MinerShare>& shares, uint64_t* bottom_height = nullptr, bool quiet = false) const;
bool get_difficulty(const PoolBlock* tip, std::vector<DifficultyData>& difficultyData, difficulty_type& curDifficulty) const; bool get_difficulty(const PoolBlock* tip, std::vector<DifficultyData>& difficultyData, difficulty_type& curDifficulty) const;
void verify_loop(PoolBlock* block); void verify_loop(PoolBlock* block);
void verify(PoolBlock* block); void verify(PoolBlock* block);

Loading…
Cancel
Save