Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auth sample disqualifications (type 2) #325

Open
wants to merge 14 commits into
base: develop
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
selectSample is made common
  • Loading branch information
AlexanderSuprunenko committed Jun 20, 2019
commit f62eceedb696ba1dd50414f9ec0e5a70c48aea90
73 changes: 73 additions & 0 deletions src/utils/sample_generator.h
Original file line number Diff line number Diff line change
@@ -104,4 +104,77 @@ uniform_select(const POD& seed, size_t count, const std::vector<T>& src, std::ve
uniform_select(do_not_seed{}, count, src, dst);
}

/*!
* \brief selectSample - selects a sample such as BBQS and QCl.
*
* \param sample_size - required resulting size.
* \param bbl_tiers - tiers of somehow sorted items.
* \param out - resulting flat list.
* \param prefix - it is for logging.
*/
constexpr int32_t TIERS = 4;

template<typename T, typename Tiers = std::array<std::vector<T>, TIERS>>
bool selectSample(size_t sample_size, const Tiers& bbl_tiers, std::vector<T>& out, const char* prefix)
{
assert(sample_size % TIERS == 0);

//select sample_size for each tier
std::array<std::vector<T>, TIERS> tier_supernodes;
for (size_t i=0; i<TIERS; ++i)
{
auto& src = bbl_tiers[i];
auto& dst = tier_supernodes[i];
dst.reserve(sample_size);
uniform_select(do_not_seed{}, sample_size, src, dst);
if (dst.size() != sample_size)
{
LOG_ERROR("unable to select supernodes for " << prefix << " sample");
return false;
}
MDEBUG("..." << dst.size() << " supernodes has been selected for tier " << (i + 1) << " from blockchain based list with " << src.size() << " supernodes");
}

auto items_per_tier = sample_size / TIERS;

std::array<int, TIERS> select;
select.fill(items_per_tier);
// If we are short of the needed SNs on any tier try selecting additional SNs from the highest
// tier with surplus SNs. For example, if tier 2 is short by 1, look for a surplus first at
// tier 4, then tier 3, then tier 1.
for (int i = 0; i < TIERS; i++) {
int deficit_i = select[i] - int(tier_supernodes[i].size());
for (int j = TIERS-1; deficit_i > 0 && j >= 0; j--) {
if (i == j) continue;
int surplus_j = int(tier_supernodes[j].size()) - select[j];
if (surplus_j > 0) {
// Tier j has more SNs than needed, so select an extra SN from tier j to make up for
// the deficiency at tier i.
int transfer = std::min(deficit_i, surplus_j);
select[i] -= transfer;
select[j] += transfer;
deficit_i -= transfer;
}
}
// If we still have a deficit then no other tier has a surplus; we'll just have to work with
// a smaller sample because there aren't enough SNs on the entire network.
if (deficit_i > 0)
select[i] -= deficit_i;
}

out.clear();
out.reserve(sample_size);
auto out_it = back_inserter(out);
for (int i = 0; i < TIERS; i++) {
std::copy(tier_supernodes[i].begin(), tier_supernodes[i].begin() + select[i], out_it);
}

if (out.size() > sample_size)
out.resize(sample_size);

MDEBUG("..." << out.size() << " supernodes has been selected");

return out.size() == sample_size;
}

}} //namespace graft::crypto_tools