Changeset View
Changeset View
Standalone View
Standalone View
src/avalanche/processor.cpp
// Copyright (c) 2018-2019 The Bitcoin developers | // Copyright (c) 2018-2019 The Bitcoin developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <avalanche/processor.h> | #include <avalanche/processor.h> | ||||
#include <avalanche/avalanche.h> | |||||
#include <avalanche/delegationbuilder.h> | #include <avalanche/delegationbuilder.h> | ||||
#include <avalanche/peermanager.h> | #include <avalanche/peermanager.h> | ||||
#include <avalanche/validation.h> | #include <avalanche/validation.h> | ||||
#include <avalanche/voterecord.h> | #include <avalanche/voterecord.h> | ||||
#include <chain.h> | #include <chain.h> | ||||
#include <key_io.h> // For DecodeSecret | #include <key_io.h> // For DecodeSecret | ||||
#include <net.h> | #include <net.h> | ||||
#include <netmessagemaker.h> | #include <netmessagemaker.h> | ||||
#include <reverse_iterator.h> | #include <reverse_iterator.h> | ||||
#include <scheduler.h> | #include <scheduler.h> | ||||
#include <util/bitmanip.h> | #include <util/bitmanip.h> | ||||
#include <util/moneystr.h> | |||||
#include <util/translation.h> | #include <util/translation.h> | ||||
#include <validation.h> | #include <validation.h> | ||||
#include <chrono> | #include <chrono> | ||||
#include <tuple> | #include <tuple> | ||||
/** | /** | ||||
* Run the avalanche event loop every 10ms. | * Run the avalanche event loop every 10ms. | ||||
▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | void updatedBlockTip() override { | ||||
} | } | ||||
m_processor->peerManager->updatedBlockTip(); | m_processor->peerManager->updatedBlockTip(); | ||||
} | } | ||||
}; | }; | ||||
Processor::Processor(const ArgsManager &argsman, interfaces::Chain &chain, | Processor::Processor(const ArgsManager &argsman, interfaces::Chain &chain, | ||||
CConnman *connmanIn, std::unique_ptr<PeerData> peerDataIn, | CConnman *connmanIn, std::unique_ptr<PeerData> peerDataIn, | ||||
CKey sessionKeyIn) | CKey sessionKeyIn, uint32_t minQuorumTotalScoreIn, | ||||
double minQuorumConnectedScoreRatioIn) | |||||
: connman(connmanIn), | : connman(connmanIn), | ||||
queryTimeoutDuration(argsman.GetArg( | queryTimeoutDuration(argsman.GetArg( | ||||
"-avatimeout", AVALANCHE_DEFAULT_QUERY_TIMEOUT.count())), | "-avatimeout", AVALANCHE_DEFAULT_QUERY_TIMEOUT.count())), | ||||
round(0), peerManager(std::make_unique<PeerManager>()), | round(0), peerManager(std::make_unique<PeerManager>()), | ||||
peerData(std::move(peerDataIn)), sessionKey(std::move(sessionKeyIn)) { | peerData(std::move(peerDataIn)), sessionKey(std::move(sessionKeyIn)), | ||||
minQuorumScore(minQuorumTotalScoreIn), | |||||
minQuorumConnectedScoreRatio(minQuorumConnectedScoreRatioIn) { | |||||
// Make sure we get notified of chain state changes. | // Make sure we get notified of chain state changes. | ||||
chainNotificationsHandler = | chainNotificationsHandler = | ||||
chain.handleNotifications(std::make_shared<NotificationsHandler>(this)); | chain.handleNotifications(std::make_shared<NotificationsHandler>(this)); | ||||
} | } | ||||
Processor::~Processor() { | Processor::~Processor() { | ||||
chainNotificationsHandler.reset(); | chainNotificationsHandler.reset(); | ||||
stopEventLoop(); | stopEventLoop(); | ||||
▲ Show 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | if (argsman.IsArgSet("-avaproof")) { | ||||
peerData->delegation = dgb->build(); | peerData->delegation = dgb->build(); | ||||
if (!VerifyDelegation(peerData->delegation, sessionPubKey, error)) { | if (!VerifyDelegation(peerData->delegation, sessionPubKey, error)) { | ||||
// error is set by VerifyDelegation | // error is set by VerifyDelegation | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
} | } | ||||
// Determine quorum parameters | |||||
Amount minQuorumStake = AVALANCHE_DEFAULT_MIN_QUORUM_STAKE; | |||||
if (gArgs.IsArgSet("-avaminquorumstake") && | |||||
!ParseMoney(gArgs.GetArg("-avaminquorumstake", ""), minQuorumStake)) { | |||||
error = _("The avalanche min quorum stake amount is invalid."); | |||||
return nullptr; | |||||
} | |||||
if (!MoneyRange(minQuorumStake)) { | |||||
error = _("The avalanche min quorum stake amount is out of range."); | |||||
return nullptr; | |||||
} | |||||
double minQuorumConnectedStakeRatio = | |||||
AVALANCHE_DEFAULT_MIN_QUORUM_CONNECTED_STAKE_RATIO; | |||||
if (gArgs.IsArgSet("-avaminquorumconnectedstakeratio") && | |||||
!ParseDouble(gArgs.GetArg("-avaminquorumconnectedstakeratio", ""), | |||||
&minQuorumConnectedStakeRatio)) { | |||||
error = _("The avalanche min quorum connected stake ratio is invalid."); | |||||
return nullptr; | |||||
} | |||||
if (minQuorumConnectedStakeRatio < 0 || minQuorumConnectedStakeRatio > 1) { | |||||
error = _( | |||||
"The avalanche min quorum connected stake ratio is out of range."); | |||||
return nullptr; | |||||
} | |||||
// We can't use std::make_unique with a private constructor | // We can't use std::make_unique with a private constructor | ||||
return std::unique_ptr<Processor>(new Processor( | return std::unique_ptr<Processor>(new Processor( | ||||
argsman, chain, connman, std::move(peerData), std::move(sessionKey))); | argsman, chain, connman, std::move(peerData), std::move(sessionKey), | ||||
Proof::amountToScore(minQuorumStake), minQuorumConnectedStakeRatio)); | |||||
} | } | ||||
bool Processor::addBlockToReconcile(const CBlockIndex *pindex) { | bool Processor::addBlockToReconcile(const CBlockIndex *pindex) { | ||||
bool isAccepted; | bool isAccepted; | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
if (!IsWorthPolling(pindex)) { | if (!IsWorthPolling(pindex)) { | ||||
▲ Show 20 Lines • Show All 407 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
void Processor::runEventLoop() { | void Processor::runEventLoop() { | ||||
// Don't do Avalanche while node is IBD'ing | // Don't do Avalanche while node is IBD'ing | ||||
if (::ChainstateActive().IsInitialBlockDownload()) { | if (::ChainstateActive().IsInitialBlockDownload()) { | ||||
return; | return; | ||||
} | } | ||||
// Don't poll if quorum hasn't been established yet | |||||
if (!isQuorumEstablished()) { | |||||
return; | |||||
} | |||||
// First things first, check if we have requests that timed out and clear | // First things first, check if we have requests that timed out and clear | ||||
// them. | // them. | ||||
clearTimedoutRequests(); | clearTimedoutRequests(); | ||||
// Make sure there is at least one suitable node to query before gathering | // Make sure there is at least one suitable node to query before gathering | ||||
// invs. | // invs. | ||||
NodeId nodeid = getSuitableNodeToQuery(); | NodeId nodeid = getSuitableNodeToQuery(); | ||||
if (nodeid == NO_NODE) { | if (nodeid == NO_NODE) { | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | do { | ||||
peerManager->removeNode(nodeid); | peerManager->removeNode(nodeid); | ||||
} | } | ||||
// Get next suitable node to try again | // Get next suitable node to try again | ||||
nodeid = getSuitableNodeToQuery(); | nodeid = getSuitableNodeToQuery(); | ||||
} while (nodeid != NO_NODE); | } while (nodeid != NO_NODE); | ||||
} | } | ||||
/* | |||||
* Returns a bool indicating whether we have a usable Avalanche quorum enabling | |||||
* us to take decisions based on polls. | |||||
*/ | |||||
bool Processor::isQuorumEstablished() { | |||||
if (quorumIsEstablished) { | |||||
return true; | |||||
} | |||||
// Get the registered proof score and registered score we have nodes for | |||||
uint32_t totalPeersScore; | |||||
uint32_t connectedPeersScore; | |||||
{ | |||||
LOCK(cs_peerManager); | |||||
totalPeersScore = peerManager->getTotalPeersScore(); | |||||
connectedPeersScore = peerManager->getConnectedPeersScore(); | |||||
} | |||||
// Ensure enough is being staked overall | |||||
if (totalPeersScore < minQuorumScore) { | |||||
return false; | |||||
} | |||||
// Ensure we have connected score for enough of the overall score | |||||
uint32_t minConnectedScore = | |||||
std::round(double(totalPeersScore) * minQuorumConnectedScoreRatio); | |||||
if (connectedPeersScore < minConnectedScore) { | |||||
return false; | |||||
} | |||||
quorumIsEstablished = true; | |||||
return true; | |||||
} | |||||
} // namespace avalanche | } // namespace avalanche |