Initial Vexta Core v0.1.0 release

This commit is contained in:
Capri 2026-07-15 14:07:28 +00:00
commit 25c454329d
2481 changed files with 689289 additions and 0 deletions

326
src/dandelion.cpp Normal file
View file

@ -0,0 +1,326 @@
// Copyright (c) 2021 The Digibyte developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
#include <config/vexta-config.h>
#endif
#include <net.h>
#include <shutdown.h>
extern bool g_ibd_complete;
bool CConnman::isDandelionInbound(const CNode* const pnode) const
{
return (std::find(vDandelionInbound.begin(), vDandelionInbound.end(), pnode) != vDandelionInbound.end());
}
bool CConnman::isLocalDandelionDestinationSet() const
{
return (localDandelionDestination != nullptr);
}
bool CConnman::setLocalDandelionDestination()
{
if (!isLocalDandelionDestinationSet()) {
localDandelionDestination = SelectFromDandelionDestinations();
LogPrint(BCLog::DANDELION, "Set local Dandelion destination:\n%s", GetDandelionRoutingDataDebugString());
}
return isLocalDandelionDestinationSet();
}
CNode* CConnman::getDandelionDestination(CNode* pfrom)
{
for (auto const& e : mDandelionRoutes) {
if (pfrom == e.first) {
return e.second;
}
}
CNode* newPto = SelectFromDandelionDestinations();
if (newPto != nullptr) {
mDandelionRoutes.insert(std::make_pair(pfrom, newPto));
LogPrint(BCLog::DANDELION, "Added Dandelion route:\n%s", GetDandelionRoutingDataDebugString());
}
return newPto;
}
bool CConnman::localDandelionDestinationPushInventory(const CInv& inv)
{
if (isLocalDandelionDestinationSet()) {
localDandelionDestination->PushOtherInventory(inv);
return true;
} else if (setLocalDandelionDestination()) {
localDandelionDestination->PushOtherInventory(inv);
return true;
} else {
return false;
}
}
bool CConnman::insertDandelionEmbargo(const uint256& hash, std::chrono::microseconds& embargo) {
auto pair = mDandelionEmbargo.insert(std::make_pair(hash, embargo));
return pair.second;
}
bool CConnman::isTxDandelionEmbargoed(const uint256& hash) const
{
auto it = mDandelionEmbargo.find(hash);
if (it == mDandelionEmbargo.end()) {
return false;
}
// Compare current time with stored embargo time
auto now = GetTime<std::chrono::microseconds>();
if (now < it->second) {
// Embargo not yet expired
return true;
}
// Otherwise, embargo expired — best practice is to remove it here or in CheckDandelionEmbargoes()
// We'll just return false, so that net_processing can proceed and eventually remove it.
return false;
}
bool CConnman::removeDandelionEmbargo(const uint256& hash)
{
bool removed = false;
for (auto iter = mDandelionEmbargo.begin(); iter != mDandelionEmbargo.end(); )
{
if (iter->first == hash) {
iter = mDandelionEmbargo.erase(iter);
removed = true;
} else {
++iter;
}
}
return removed;
}
CNode* CConnman::SelectFromDandelionDestinations() const
{
std::map<CNode*, uint64_t> mDandelionDestinationCounts;
for (size_t i = 0; i < vDandelionDestination.size(); i++) {
mDandelionDestinationCounts.insert(std::make_pair(vDandelionDestination.at(i), 0));
}
for (auto& e : mDandelionDestinationCounts) {
for (auto const& f : mDandelionRoutes) {
if (e.first == f.second) {
e.second += 1;
}
}
}
unsigned int minNumConnections = vDandelionInbound.size();
for (auto const& e : mDandelionDestinationCounts) {
if (e.second < minNumConnections) {
minNumConnections = e.second;
}
}
std::vector<CNode*> candidateDestinations;
for (auto const& e : mDandelionDestinationCounts) {
if (e.second == minNumConnections) {
candidateDestinations.push_back(e.first);
}
}
FastRandomContext rng;
CNode* dandelionDestination = nullptr;
if (candidateDestinations.size() > 0) {
dandelionDestination = candidateDestinations.at(rng.randrange(candidateDestinations.size()));
}
return dandelionDestination;
}
void CConnman::CloseDandelionConnections(const CNode* const pnode)
{
// Remove pnode from vDandelionInbound, if present
for (auto iter = vDandelionInbound.begin(); iter != vDandelionInbound.end();) {
if (*iter == pnode) {
iter = vDandelionInbound.erase(iter);
} else {
iter++;
}
}
// Remove pnode from vDandelionOutbound, if present
for (auto iter = vDandelionOutbound.begin(); iter != vDandelionOutbound.end();) {
if (*iter == pnode) {
iter = vDandelionOutbound.erase(iter);
} else {
iter++;
}
}
// Remove pnode from vDandelionDestination, if present
bool isDandelionDestination = false;
for (auto iter = vDandelionDestination.begin(); iter != vDandelionDestination.end();) {
if (*iter == pnode) {
isDandelionDestination = true;
iter = vDandelionDestination.erase(iter);
} else {
iter++;
}
}
// Generate a replacement Dandelion destination, if necessary
if (isDandelionDestination) {
// Gather a vector of candidate replacements (outbound peers that are not already destinations)
std::vector<CNode*> candidateReplacements;
for (auto iteri = vDandelionOutbound.begin(); iteri != vDandelionOutbound.end();) {
bool eligibleCandidate = true;
for (auto iterj = vDandelionDestination.begin(); iterj != vDandelionDestination.end();) {
if (*iteri == *iterj) {
eligibleCandidate = false;
iterj = vDandelionDestination.end();
} else {
iterj++;
}
}
if (eligibleCandidate) {
candidateReplacements.push_back(*iteri);
}
iteri++;
}
// Select a candidate to be the replacement destination
FastRandomContext rng;
CNode* replacementDestination = nullptr;
if (candidateReplacements.size() > 0) {
replacementDestination = candidateReplacements.at(rng.randrange(candidateReplacements.size()));
}
if (replacementDestination != nullptr) {
vDandelionDestination.push_back(replacementDestination);
}
}
// Generate a replacement pnode, to be used if necessary
CNode* newPto = SelectFromDandelionDestinations();
// Remove from mDandelionRoutes, if present; if destination, try to replace
for (auto iter = mDandelionRoutes.begin(); iter != mDandelionRoutes.end();) {
if (iter->first == pnode) {
iter = mDandelionRoutes.erase(iter);
} else if (iter->second == pnode) {
if (newPto == nullptr) {
iter = mDandelionRoutes.erase(iter);
} else {
iter->second = newPto;
iter++;
}
} else {
iter++;
}
}
// Replace localDandelionDestination if equal to pnode
if (localDandelionDestination == pnode) {
localDandelionDestination = newPto;
}
}
std::string CConnman::GetDandelionRoutingDataDebugString() const
{
std::string dandelionRoutingDataDebugString = "";
dandelionRoutingDataDebugString.append(" vDandelionInbound: ");
for (auto const& e : vDandelionInbound) {
dandelionRoutingDataDebugString.append(std::to_string(e->GetId()) + " ");
}
dandelionRoutingDataDebugString.append("\n vDandelionOutbound: ");
for (auto const& e : vDandelionOutbound) {
dandelionRoutingDataDebugString.append(std::to_string(e->GetId()) + " ");
}
dandelionRoutingDataDebugString.append("\n vDandelionDestination: ");
for (auto const& e : vDandelionDestination) {
dandelionRoutingDataDebugString.append(std::to_string(e->GetId()) + " ");
}
dandelionRoutingDataDebugString.append("\n mDandelionRoutes: ");
for (auto const& e : mDandelionRoutes) {
dandelionRoutingDataDebugString.append("(" + std::to_string(e.first->GetId()) + "," + std::to_string(e.second->GetId()) + ") ");
}
dandelionRoutingDataDebugString.append("\n localDandelionDestination: ");
if (!localDandelionDestination) {
dandelionRoutingDataDebugString.append("nullptr");
} else {
dandelionRoutingDataDebugString.append(std::to_string(localDandelionDestination->GetId()));
}
dandelionRoutingDataDebugString.append("\n");
return dandelionRoutingDataDebugString;
}
void CConnman::DandelionShuffle()
{
// Dandelion debug message
LogPrint(BCLog::DANDELION, "Before Dandelion shuffle:\n%s", GetDandelionRoutingDataDebugString());
{
// Lock node pointers
LOCK(cs_vNodes);
// Iterate through mDandelionRoutes to facilitate bookkeeping
for (auto iter = mDandelionRoutes.begin(); iter != mDandelionRoutes.end();) {
iter = mDandelionRoutes.erase(iter);
}
// Set localDandelionDestination to nulltpr and perform bookkeeping
if (localDandelionDestination != nullptr) {
localDandelionDestination = nullptr;
}
// Clear vDandelionDestination
// (bookkeeping already done while iterating through mDandelionRoutes)
vDandelionDestination.clear();
// Repopulate vDandelionDestination
while (vDandelionDestination.size() < DANDELION_MAX_DESTINATIONS && vDandelionDestination.size() < vDandelionOutbound.size()) {
std::vector<CNode*> candidateDestinations;
for (auto iteri = vDandelionOutbound.begin(); iteri != vDandelionOutbound.end();) {
bool eligibleCandidate = true;
for (auto iterj = vDandelionDestination.begin(); iterj != vDandelionDestination.end();) {
if (*iteri == *iterj) {
eligibleCandidate = false;
iterj = vDandelionDestination.end();
} else {
iterj++;
}
}
if (eligibleCandidate) {
candidateDestinations.push_back(*iteri);
}
iteri++;
}
FastRandomContext rng;
if (candidateDestinations.size() > 0) {
vDandelionDestination.push_back(candidateDestinations.at(rng.randrange(candidateDestinations.size())));
} else {
break;
}
}
// Generate new routes
for (auto pnode : vDandelionInbound) {
CNode* pto = SelectFromDandelionDestinations();
if (pto) {
mDandelionRoutes.insert(std::make_pair(pnode, pto));
}
}
localDandelionDestination = SelectFromDandelionDestinations();
}
// Dandelion debug message
LogPrint(BCLog::DANDELION, "After Dandelion shuffle:\n%s", GetDandelionRoutingDataDebugString());
}
void CConnman::ThreadDandelionShuffle()
{
while (!ShutdownRequested()) {
UninterruptibleSleep(std::chrono::milliseconds{1000});
if (g_ibd_complete) {
break;
}
if(ShutdownRequested()) {
return;
}
}
auto now = GetTime<std::chrono::microseconds>();
auto nNextDandelionShuffle = PoissonNextSend(now, DANDELION_SHUFFLE_INTERVAL);
while (!ShutdownRequested()) {
now = GetTime<std::chrono::milliseconds>();
if (now > nNextDandelionShuffle) {
DandelionShuffle();
nNextDandelionShuffle = PoissonNextSend(now, DANDELION_SHUFFLE_INTERVAL);
}
if (ShutdownRequested()) {
return;
}
if (!interruptNet.sleep_for(std::chrono::milliseconds(100))) {
return;
}
}
}