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

Disqualification samples generation #271

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
31 changes: 27 additions & 4 deletions include/rta/fullsupernodelist.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ class FullSupernodeList
static constexpr int32_t TIERS = 4;
static constexpr int32_t ITEMS_PER_TIER = 2;
static constexpr int32_t AUTH_SAMPLE_SIZE = TIERS * ITEMS_PER_TIER;
static constexpr int32_t DISQUALIFICATION_SAMPLE_SIZE = AUTH_SAMPLE_SIZE;
static constexpr int32_t DISQUALIFICATION_CANDIDATES_SIZE = AUTH_SAMPLE_SIZE;
static constexpr int64_t AUTH_SAMPLE_HASH_HEIGHT = 20; // block number for calculating auth sample should be calculated as current block height - AUTH_SAMPLE_HASH_HEIGHT;
static constexpr int64_t ANNOUNCE_TTL_SECONDS = 60 * 60; // if more than ANNOUNCE_TTL_SECONDS passed from last annouce - supernode excluded from auth sample selection

Expand Down Expand Up @@ -98,6 +100,15 @@ class FullSupernodeList

bool buildAuthSample(const std::string& payment_id, supernode_array &out, uint64_t &out_auth_block_number);

/*!
* \brief buildDisqualificationSamples - builds disqualification samples for given block height
* \param height - block height used to perform selectio
* \param out_disqualification_sample - vector of supernode pointers which should check other nodes
* \param out_nodes_for_check - vector of supernode pointers which should be checked
* \return - true on success
*/
bool buildDisqualificationSamples(uint64_t height, supernode_array &out_disqualification_sample, supernode_array &out_disqualification_candidates);

/*!
* \brief items - returns address list of known supernodes
* \return
Expand Down Expand Up @@ -143,8 +154,18 @@ class FullSupernodeList
};

typedef std::vector<blockchain_based_list_entry> blockchain_based_list_tier;
typedef std::vector<blockchain_based_list_tier> blockchain_based_list;
typedef std::shared_ptr<blockchain_based_list> blockchain_based_list_ptr;
typedef std::vector<blockchain_based_list_tier> blockchain_based_list_tier_array;

struct blockchain_based_list
{
std::string block_hash;
blockchain_based_list_tier_array tiers;

blockchain_based_list() {}
blockchain_based_list(const std::string& in_block_hash) : block_hash(in_block_hash) {}
};

typedef std::shared_ptr<blockchain_based_list> blockchain_based_list_ptr;

/*!
* \brief setBlockchainBasedList - updates full list of supernodes
Expand Down Expand Up @@ -184,9 +205,10 @@ class FullSupernodeList
* \brief getBlockchainBasedListForAuthSample - builds blockchain based list for specified block height and removes nodes which are not reachable
* \param block_number - block height used to list building
* \param out_list - resulting list
* \param use_delay - should delay be used for shifting block number
* \return - block number which was used for base list
*/
uint64_t getBlockchainBasedListForAuthSample(uint64_t block_number, blockchain_based_list& list) const;
uint64_t getBlockchainBasedListForAuthSample(uint64_t block_number, blockchain_based_list& list, bool use_delay = true) const;

/*!
* \brief synchronizeWithCryptonode - synchronize with cryptonode
Expand All @@ -203,7 +225,8 @@ class FullSupernodeList
private:
// bool loadWallet(const std::string &wallet_path);
void addImpl(SupernodePtr item);
bool selectSupernodes(size_t items_count, const std::string& payment_id, const blockchain_based_list_tier& src_array, supernode_array& dst_array);
bool selectSupernodes(size_t items_count, const blockchain_based_list_tier& src_array, supernode_array& dst_array);
bool buildSample(const blockchain_based_list& bbl, size_t sample_size, const char* prefix, supernode_array &out);

typedef std::unordered_map<uint64_t, blockchain_based_list_ptr> blockchain_based_list_map;

Expand Down
1 change: 1 addition & 0 deletions include/supernode/requests/blockchain_based_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ GRAFT_DEFINE_IO_STRUCT_INITED(BlockchainBasedListTier,

GRAFT_DEFINE_IO_STRUCT_INITED(BlockchainBasedList,
(uint64_t, block_height, uint64_t()),
(std::string, block_hash, std::string()),
(std::vector<BlockchainBasedListTier>, tiers, std::vector<BlockchainBasedListTier>())
);

Expand Down
161 changes: 90 additions & 71 deletions src/rta/fullsupernodelist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ SupernodePtr FullSupernodeList::get(const string &address) const
return SupernodePtr(nullptr);
}

bool FullSupernodeList::selectSupernodes(size_t items_count, const std::string& payment_id, const blockchain_based_list_tier& src_array, supernode_array& dst_array)
bool FullSupernodeList::selectSupernodes(size_t items_count, const blockchain_based_list_tier& src_array, supernode_array& dst_array)
{
size_t src_array_size = src_array.size();

Expand Down Expand Up @@ -278,11 +278,14 @@ bool FullSupernodeList::selectSupernodes(size_t items_count, const std::string&
return true;
}

uint64_t FullSupernodeList::getBlockchainBasedListForAuthSample(uint64_t block_number, blockchain_based_list& list) const
uint64_t FullSupernodeList::getBlockchainBasedListForAuthSample(uint64_t block_number, blockchain_based_list& list, bool use_delay) const
{
boost::shared_lock<boost::shared_mutex> readerLock(m_access);

uint64_t blockchain_based_list_height = block_number - BLOCKCHAIN_BASED_LIST_DELAY_BLOCK_COUNT;
uint64_t blockchain_based_list_height = block_number;

if (use_delay)
blockchain_based_list_height -= BLOCKCHAIN_BASED_LIST_DELAY_BLOCK_COUNT;

blockchain_based_list_map::const_iterator it = m_blockchain_based_lists.find(block_number);

Expand All @@ -292,7 +295,9 @@ uint64_t FullSupernodeList::getBlockchainBasedListForAuthSample(uint64_t block_n
blockchain_based_list result;
blockchain_based_list_ptr bbl = it->second;

for (blockchain_based_list_tier& src : *bbl)
result.block_hash = bbl->block_hash;

for (blockchain_based_list_tier& src : bbl->tiers)
{
blockchain_based_list_tier dst;

Expand All @@ -312,68 +317,34 @@ uint64_t FullSupernodeList::getBlockchainBasedListForAuthSample(uint64_t block_n
return true;
});

result.emplace_back(std::move(dst));
result.tiers.emplace_back(std::move(dst));
}

list.swap(result);
list = std::move(result);

return blockchain_based_list_height;
}

bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& payment_id, supernode_array &out, uint64_t &out_auth_block_number)
bool FullSupernodeList::buildSample(const blockchain_based_list& bbl, size_t sample_size, const char* prefix, supernode_array &out)
{
blockchain_based_list bbl;
std::array<supernode_array, TIERS> tier_supernodes;

out_auth_block_number = getBlockchainBasedListForAuthSample(height, bbl);
//select supernodes for a full supernode list

if (!out_auth_block_number)
for (size_t i=0, tiers_count=bbl.tiers.size(); i<TIERS && i<tiers_count; i++)
{
LOG_ERROR("unable to build auth sample for block height " << height << " (blockchain_based_list_height=" << (height - BLOCKCHAIN_BASED_LIST_DELAY_BLOCK_COUNT) << ") and PaymentID "
<< payment_id << ". Blockchain based list for this block is absent, latest block is " << getBlockchainBasedListMaxBlockNumber());
return false;
}

MDEBUG("building auth sample for height " << height << " (blockchain_based_list_height=" << out_auth_block_number << ") and PaymentID '" << payment_id << "'");
const blockchain_based_list_tier& src_array = bbl.tiers[i];
supernode_array& dst_array = tier_supernodes[i];

dst_array.reserve(sample_size);

std::array<supernode_array, TIERS> tier_supernodes;
{
boost::unique_lock<boost::shared_mutex> writerLock(m_access);

//seed RNG

std::seed_seq seed(reinterpret_cast<const unsigned char*>(payment_id.c_str()),
reinterpret_cast<const unsigned char*>(payment_id.c_str() + payment_id.size()));

m_rng.seed(seed);

//select supernodes for a full supernode list

MDEBUG("use blockchain based list for height " << out_auth_block_number);
int t = 1;
for (const blockchain_based_list_tier& l : bbl)
if (!selectSupernodes(sample_size, src_array, dst_array))
{
MDEBUG("...tier #" << t);
int j=0;
for (const blockchain_based_list_entry& e : l)
MDEBUG(".....[" << j++ << "]=" << e.supernode_public_id);
t++;
LOG_ERROR("unable to select supernodes for " << prefix << " sample");
return false;
}

for (size_t i=0, tiers_count=bbl.size(); i<TIERS && i<tiers_count; i++)
{
const blockchain_based_list_tier& src_array = bbl[i];
supernode_array& dst_array = tier_supernodes[i];

dst_array.reserve(AUTH_SAMPLE_SIZE);

if (!selectSupernodes(AUTH_SAMPLE_SIZE, payment_id, src_array, dst_array))
{
LOG_ERROR("unable to select supernodes for auth sample");
return false;
}

MDEBUG("..." << dst_array.size() << " supernodes has been selected for tier " << (i + 1) << " from blockchain based list with " << src_array.size() << " supernodes");
}
MDEBUG("..." << dst_array.size() << " supernodes has been selected for tier " << (i + 1) << " from blockchain based list with " << src_array.size() << " supernodes");
}

array<int, TIERS> select;
Expand Down Expand Up @@ -409,31 +380,90 @@ bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& paym
}

if (VLOG_IS_ON(2)) {
std::string auth_sample_str, tier_sample_str;
std::string sample_str, tier_sample_str;
for (const auto &a : out) {
auth_sample_str += a->idKeyAsString() + "\n";
sample_str += a->idKeyAsString() + "\n";
}
for (size_t i = 0; i < select.size(); i++) {
if (i > 0) tier_sample_str += ", ";
tier_sample_str += std::to_string(select[i]) + " T" + std::to_string(i+1);
}
MDEBUG("selected " << tier_sample_str << " supernodes of " << size() << " for auth sample");
MTRACE("auth sample: \n" << auth_sample_str);
MDEBUG("selected " << tier_sample_str << " supernodes of " << size() << " for " << prefix << " sample");
MTRACE(prefix << " sample: \n" << sample_str);
}

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

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

return out.size() == AUTH_SAMPLE_SIZE;
return out.size() == sample_size;
}

bool FullSupernodeList::buildAuthSample(uint64_t height, const std::string& payment_id, supernode_array &out, uint64_t &out_auth_block_number)
{
blockchain_based_list bbl;

out_auth_block_number = getBlockchainBasedListForAuthSample(height, bbl);

if (!out_auth_block_number)
{
LOG_ERROR("unable to build auth sample for block height " << height << " (blockchain_based_list_height=" << (height - BLOCKCHAIN_BASED_LIST_DELAY_BLOCK_COUNT) << ") and PaymentID "
<< payment_id << ". Blockchain based list for this block is absent, latest block is " << getBlockchainBasedListMaxBlockNumber());
return false;
}

MDEBUG("building auth sample for height " << height << " (blockchain_based_list_height=" << out_auth_block_number << ") and PaymentID '" << payment_id << "'");

boost::unique_lock<boost::shared_mutex> writerLock(m_access);

//seed RNG

std::seed_seq seed(reinterpret_cast<const unsigned char*>(payment_id.c_str()),
reinterpret_cast<const unsigned char*>(payment_id.c_str() + payment_id.size()));

m_rng.seed(seed);

//build sample

return buildSample(bbl, AUTH_SAMPLE_SIZE, "auth", out);
}

bool FullSupernodeList::buildAuthSample(const string &payment_id, FullSupernodeList::supernode_array &out, uint64_t &out_auth_block_number)
{
return buildAuthSample(getBlockchainBasedListMaxBlockNumber(), payment_id, out, out_auth_block_number);
}

bool FullSupernodeList::buildDisqualificationSamples(uint64_t height, supernode_array &out_disqualification_sample, supernode_array &out_disqualification_candidates)
{
blockchain_based_list bbl;

uint64_t out_auth_block_number = getBlockchainBasedListForAuthSample(height, bbl, false);

if (!out_auth_block_number)
{
LOG_ERROR("unable to build disqualification samples for block height " << height << " (blockchain_based_list_height=" << (height - BLOCKCHAIN_BASED_LIST_DELAY_BLOCK_COUNT) << ") "
". Blockchain based list for this block is absent, latest block is " << getBlockchainBasedListMaxBlockNumber());
return false;
}

MDEBUG("building disqualification samples for height " << height << " (blockchain_based_list_height=" << out_auth_block_number << ") and hash=" << bbl.block_hash);

boost::unique_lock<boost::shared_mutex> writerLock(m_access);

//seed RNG

std::seed_seq seed(reinterpret_cast<const unsigned char*>(bbl.block_hash.c_str()),
reinterpret_cast<const unsigned char*>(bbl.block_hash.c_str() + bbl.block_hash.size()));

m_rng.seed(seed);

//build sample

return buildSample(bbl, DISQUALIFICATION_SAMPLE_SIZE, "disqualification", out_disqualification_sample) &&
buildSample(bbl, DISQUALIFICATION_CANDIDATES_SIZE, "disqualification candidates", out_disqualification_candidates);
}

vector<string> FullSupernodeList::items() const
{
boost::shared_lock<boost::shared_mutex> readerLock(m_access);
Expand Down Expand Up @@ -575,17 +605,6 @@ void FullSupernodeList::setBlockchainBasedList(uint64_t block_number, const bloc
{
boost::unique_lock<boost::shared_mutex> writerLock(m_access);

MDEBUG("update blockchain based list for height " << block_number);
int t = 1;
for (const blockchain_based_list_tier& l : *list)
{
MDEBUG("...tier #" << t);
int j=0;
for (const blockchain_based_list_entry& e : l)
MDEBUG(".....[" << j++ << "]=" << e.supernode_public_id);
t++;
}

blockchain_based_list_map::iterator it = m_blockchain_based_lists.find(block_number);

if (it != m_blockchain_based_lists.end())
Expand Down Expand Up @@ -637,7 +656,7 @@ size_t FullSupernodeList::getSupernodeBlockchainBasedListTier(const std::string&

size_t tier_number = 1;

for (const blockchain_based_list_tier& tier : *list)
for (const blockchain_based_list_tier& tier : list->tiers)
{
for (const blockchain_based_list_entry& sn : tier)
if (sn.supernode_public_id == supernode_public_id)
Expand Down
6 changes: 3 additions & 3 deletions src/supernode/requests/blockchain_based_list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ Status blockchainBasedListHandler

//handle tiers

FullSupernodeList::blockchain_based_list tiers;
FullSupernodeList::blockchain_based_list bbl(req.params.block_hash);

for (const BlockchainBasedListTier& tier : req.params.tiers)
{
Expand All @@ -99,11 +99,11 @@ Status blockchainBasedListHandler
supernodes.emplace_back(std::move(entry));
}

tiers.emplace_back(std::move(supernodes));
bbl.tiers.emplace_back(std::move(supernodes));
}

fsl->setBlockchainBasedList(req.params.block_height, FullSupernodeList::blockchain_based_list_ptr(
new FullSupernodeList::blockchain_based_list(std::move(tiers))));
new FullSupernodeList::blockchain_based_list(std::move(bbl))));

return Status::Ok;
}
Expand Down
4 changes: 2 additions & 2 deletions src/supernode/requests/debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ Status getSupernodeList(const Router::vars_t& vars, const graft::Input& input,

auto is_supernode_available = [&](const std::string& supernode_public_id)
{
for (const FullSupernodeList::blockchain_based_list_tier& tier : auth_sample_base_list)
for (const FullSupernodeList::blockchain_based_list_tier& tier : auth_sample_base_list.tiers)
{
for (const FullSupernodeList::blockchain_based_list_entry& entry : tier)
if (supernode_public_id == entry.supernode_public_id)
Expand Down Expand Up @@ -235,7 +235,7 @@ Status getBlockchainBasedListImpl(const Router::vars_t& vars, const graft::Input
}
}

for (const FullSupernodeList::blockchain_based_list_tier& src_tier : bbl)
for (const FullSupernodeList::blockchain_based_list_tier& src_tier : bbl.tiers)
{
std::vector<DbgBlockchainBasedListEntry> dst_tier;

Expand Down