Optimized `get_shares`

pull/1/head
SChernykh 1 year ago
parent 850eb8e6e0
commit 4f2ad9a93c

@ -335,9 +335,6 @@ bool SideChain::get_shares(const PoolBlock* tip, std::vector<MinerShare>& shares
const int L = quiet ? 6 : 3;
shares.clear();
shares.reserve(m_chainWindowSize * 2);
// Collect shares from each block in the PPLNS window, starting from the "tip"
uint64_t block_depth = 0;
@ -363,8 +360,11 @@ bool SideChain::get_shares(const PoolBlock* tip, std::vector<MinerShare>& shares
const difficulty_type max_pplns_weight = (sidechain_version > 1) ? (mainchain_diff * 2) : diff_max;
difficulty_type pplns_weight;
unordered_set<MinerShare> shares_set;
shares_set.reserve(m_chainWindowSize * 2);
do {
MinerShare cur_share{ cur->m_difficulty, &cur->m_minerWallet };
difficulty_type cur_weight = cur->m_difficulty;
for (const hash& uncle_id : cur->m_uncles) {
auto it = m_blocksById.find(uncle_id);
@ -391,15 +391,21 @@ bool SideChain::get_shares(const PoolBlock* tip, std::vector<MinerShare>& shares
continue;
}
cur_share.m_weight += uncle_penalty;
cur_weight += uncle_penalty;
shares.emplace_back(uncle_weight, &uncle->m_minerWallet);
auto result = shares_set.emplace(uncle_weight, &uncle->m_minerWallet);
if (!result.second) {
result.first->m_weight += uncle_weight;
}
pplns_weight = new_pplns_weight;
}
// Always add non-uncle shares even if PPLNS weight goes above the limit
shares.push_back(cur_share);
pplns_weight += cur_share.m_weight;
auto result = shares_set.emplace(cur_weight, &cur->m_minerWallet);
if (!result.second) {
result.first->m_weight += cur_weight;
}
pplns_weight += cur_weight;
// One non-uncle share can go above the limit, but it will also guarantee that "shares" is never empty
if (pplns_weight > max_pplns_weight) {
@ -426,34 +432,27 @@ bool SideChain::get_shares(const PoolBlock* tip, std::vector<MinerShare>& shares
cur = it->second;
} while (true);
// Combine shares with the same wallet addresses
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; });
size_t k = 0;
for (size_t i = 1, n = shares.size(); i < n; ++i)
{
if (*shares[i].m_wallet == *shares[k].m_wallet) {
shares[k].m_weight += shares[i].m_weight;
}
else {
++k;
shares[k].m_weight = shares[i].m_weight;
shares[k].m_wallet = shares[i].m_wallet;
}
}
shares.resize(k + 1);
LOGINFO(6, "get_shares: " << k + 1 << " unique wallets in PPLNS window");
const uint64_t n = shares.size();
// Shuffle shares
if (sidechain_version > 1) {
std::mt19937_64 rng(*reinterpret_cast<const uint64_t*>(tip->m_txkeySecSeed.h));
if ((sidechain_version > 1) && (n > 1)) {
hash h;
keccak(tip->m_txkeySecSeed.h, HASH_SIZE, h.h);
uint64_t seed = *reinterpret_cast<uint64_t*>(h.h);
if (seed == 0) seed = 1;
for (int64_t i = k; i > 0; --i) {
std::swap(shares[i], shares[rng() % (i + 1)]);
for (uint64_t i = 0, k; i < n - 1; ++i) {
seed = xorshift64star(seed);
umul128(seed, n - i, &k);
std::swap(shares[i], shares[i + k]);
}
}
LOGINFO(6, "get_shares: " << n << " unique wallets in PPLNS window");
return true;
}

@ -32,6 +32,8 @@ struct MinerShare
FORCEINLINE MinerShare() : m_weight(), m_wallet(nullptr) {}
FORCEINLINE MinerShare(const difficulty_type& w, const Wallet* x) : m_weight(w), m_wallet(x) {}
FORCEINLINE bool operator==(const MinerShare& s) const { return *m_wallet == *s.m_wallet; }
difficulty_type m_weight;
const Wallet* m_wallet;
};
@ -157,3 +159,16 @@ private:
};
} // namespace p2pool
namespace robin_hood {
template<>
struct hash<p2pool::MinerShare>
{
FORCEINLINE size_t operator()(const p2pool::MinerShare& value) const noexcept
{
return hash_bytes(value.m_wallet->spend_public_key().h, p2pool::HASH_SIZE);
}
};
} // namespace robin_hood

@ -208,6 +208,14 @@ struct RandomDeviceSeed
static RandomDeviceSeed instance;
};
FORCEINLINE uint64_t xorshift64star(uint64_t x)
{
x ^= x >> 12;
x ^= x << 25;
x ^= x >> 27;
return x * 0x2545F4914F6CDD1DULL;
}
FORCEINLINE uint64_t seconds_since_epoch()
{
using namespace std::chrono;

Loading…
Cancel
Save