Skip to content

Commit

Permalink
Merge branch 'master' into bench
Browse files Browse the repository at this point in the history
  • Loading branch information
sisuresh committed Sep 17, 2024
2 parents 7aa8bf2 + d2e025e commit 5fe4199
Show file tree
Hide file tree
Showing 13 changed files with 885 additions and 115 deletions.
4 changes: 4 additions & 0 deletions docs/stellar-core_example.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,10 @@ EMIT_SOROBAN_TRANSACTION_META_EXT_V1=false
# https://github.com/stellar/stellar-xdr/commit/cdc339f5e74a75e8e558fd1a853397da71f1659a
EMIT_LEDGER_CLOSE_META_EXT_V1=false

# When set to true, Core will revert to using the old, application-agnostic
# nomination weight function for SCP leader election.
FORCE_OLD_STYLE_LEADER_ELECTION=false

# EXCLUDE_TRANSACTIONS_CONTAINING_OPERATION_TYPE (list of strings) default is empty
# Setting this will cause the node to reject transactions that it receives if
# they contain any operation in this list. It will not, however, stop the node
Expand Down
68 changes: 68 additions & 0 deletions src/herder/HerderSCPDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "xdr/Stellar-ledger.h"
#include <Tracy.hpp>
#include <algorithm>
#include <cmath>
#include <fmt/format.h>
#include <medida/metrics_registry.h>
#include <numeric>
Expand Down Expand Up @@ -1284,4 +1285,71 @@ HerderSCPDriver::TxSetValidityKeyHash::operator()(
hashMix(res, std::get<3>(key));
return res;
}

uint64
HerderSCPDriver::getNodeWeight(NodeID const& nodeID, SCPQuorumSet const& qset,
bool const isLocalNode) const
{
Config const& cfg = mApp.getConfig();
bool const unsupportedProtocol = protocolVersionIsBefore(
mApp.getLedgerManager()
.getLastClosedLedgerHeader()
.header.ledgerVersion,
APPLICATION_SPECIFIC_NOMINATION_LEADER_ELECTION_PROTOCOL_VERSION);
if (unsupportedProtocol || !cfg.VALIDATOR_WEIGHT_CONFIG.has_value() ||
cfg.FORCE_OLD_STYLE_LEADER_ELECTION)
{
// Fall back on old weight algorithm if any of the following are true:
// 1. The network has not yet upgraded to
// APPLICATION_SPECIFIC_NOMINATION_LEADER_ELECTION_PROTOCOL_VERSION,
// 2. The node is using manual quorum set configuration, or
// 3. The node has the FORCE_OLD_STYLE_LEADER_ELECTION flag
// set
return SCPDriver::getNodeWeight(nodeID, qset, isLocalNode);
}

ValidatorWeightConfig const& vwc =
mApp.getConfig().VALIDATOR_WEIGHT_CONFIG.value();

auto entryIt = vwc.mValidatorEntries.find(nodeID);
if (entryIt == vwc.mValidatorEntries.end())
{
// This shouldn't be possible as the validator entries should contain
// all validators in the config. For this to happen, `getNodeWeight`
// would have to be called with a non-validator `nodeID`. Throw if
// building tests, and otherwise fall back on the old algorithm.
throw std::runtime_error(
fmt::format(FMT_STRING("Validator entry not found for node {}"),
toShortString(nodeID)));
}

ValidatorEntry const& entry = entryIt->second;
auto homeDomainSizeIt = vwc.mHomeDomainSizes.find(entry.mHomeDomain);
if (homeDomainSizeIt == vwc.mHomeDomainSizes.end())
{
// This shouldn't be possible as the home domain sizes should contain
// all home domains in the config. For this to happen, `getNodeWeight`
// would have to be called with a non-validator, or the config parser
// would have to allow a validator without a home domain. Throw if
// building tests, and otherwise fall back on the old algorithm.
throw std::runtime_error(
fmt::format(FMT_STRING("Home domain size not found for domain {}"),
entry.mHomeDomain));
}

auto qualityWeightIt = vwc.mQualityWeights.find(entry.mQuality);
if (qualityWeightIt == vwc.mQualityWeights.end())
{
// This shouldn't be possible as the quality weights should contain all
// quality levels in the config.
throw std::runtime_error(
fmt::format(FMT_STRING("Quality weight not found for quality {}"),
static_cast<int>(entry.mQuality)));
}

// Node's weight is its quality's weight divided by the number of nodes in
// its home domain
releaseAssert(homeDomainSizeIt->second > 0);
return qualityWeightIt->second / homeDomainSizeIt->second;
}
}
14 changes: 14 additions & 0 deletions src/herder/HerderSCPDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "herder/TxSetUtils.h"
#include "medida/timer.h"
#include "scp/SCPDriver.h"
#include "util/ProtocolVersion.h"
#include "util/RandomEvictionCache.h"
#include "xdr/Stellar-ledger.h"
#include <optional>
Expand All @@ -32,6 +33,11 @@ class VirtualTimer;
struct StellarValue;
struct SCPEnvelope;

// First protocol version supporting the application-specific weight function
// for SCP leader election.
ProtocolVersion constexpr APPLICATION_SPECIFIC_NOMINATION_LEADER_ELECTION_PROTOCOL_VERSION =
ProtocolVersion::V_22;

class HerderSCPDriver : public SCPDriver
{
public:
Expand Down Expand Up @@ -129,6 +135,14 @@ class HerderSCPDriver : public SCPDriver

Json::Value getQsetLagInfo(bool summary, bool fullKeys);

// Application-specific weight function. This function uses the quality
// levels from automatic quorum set generation to determine the weight of a
// validator. It is designed to ensure that:
// 1. Orgs of equal quality have equal chances of winning leader election.
// 2. Higher quality orgs win more frequently than lower quality orgs.
uint64 getNodeWeight(NodeID const& nodeID, SCPQuorumSet const& qset,
bool isLocalNode) const override;

private:
Application& mApp;
HerderImpl& mHerder;
Expand Down
Loading

0 comments on commit 5fe4199

Please sign in to comment.