Compare commits

...

1 Commits

Author SHA1 Message Date
Richard Holland
574593ea3d webrtc support 2026-10-04 17:14:57 +11:00
14 changed files with 153 additions and 5 deletions

View File

@@ -244,6 +244,9 @@ public:
// Enable the experimental Ledger Replay functionality
bool LEDGER_REPLAY = false;
// Maximum inbound light peers ([light_peers]); 0 disables light mode
std::size_t LIGHT_PEERS_MAX = 0;
// Work queue limits
int MAX_TRANSACTIONS = 1000;
static constexpr int MAX_JOB_QUEUE_TX = 1000;

View File

@@ -59,6 +59,7 @@ struct ConfigSection
#define SECTION_IPS_FIXED "ips_fixed"
#define SECTION_LEDGER_HISTORY "ledger_history"
#define SECTION_LEDGER_REPLAY "ledger_replay"
#define SECTION_LIGHT_PEERS "light_peers"
#define SECTION_MAX_TRANSACTIONS "max_transactions"
#define SECTION_NETWORK_ID "network_id"
#define SECTION_NETWORK_QUORUM "network_quorum"

View File

@@ -732,6 +732,9 @@ Config::loadFromString(std::string const& fileContents)
if (getSingleSection(secConfig, SECTION_LEDGER_REPLAY, strTemp, j_))
LEDGER_REPLAY = beast::lexicalCastThrow<bool>(strTemp);
if (getSingleSection(secConfig, SECTION_LIGHT_PEERS, strTemp, j_))
LIGHT_PEERS_MAX = beast::lexicalCastThrow<std::size_t>(strTemp);
if (exists(SECTION_REDUCE_RELAY))
{
auto sec = section(SECTION_REDUCE_RELAY);

View File

@@ -93,6 +93,13 @@ public:
return category_;
}
/** Get the protocol message type */
int
getType() const
{
return type_;
}
/** Get the validator's key */
std::optional<PublicKey> const&
getValidatorKey() const
@@ -104,6 +111,7 @@ private:
std::vector<uint8_t> buffer_;
std::vector<uint8_t> bufferCompressed_;
std::size_t category_;
int type_;
std::once_flag once_flag_;
std::optional<PublicKey> validatorKey_;

View File

@@ -133,6 +133,14 @@ public:
virtual bool
txReduceRelayEnabled() const = 0;
/** A light peer (X-Protocol-Ctl: light=1): never used to acquire data,
never sent proposals or transactions. */
virtual bool
isLight() const
{
return false;
}
};
} // namespace ripple

View File

@@ -93,9 +93,12 @@ makeFeaturesResponseHeader(
bool comprEnabled,
bool ledgerReplayEnabled,
bool txReduceRelayEnabled,
bool vpReduceRelayEnabled)
bool vpReduceRelayEnabled,
bool lightEnabled)
{
std::stringstream str;
if (lightEnabled && featureEnabled(headers, FEATURE_LIGHT))
str << FEATURE_LIGHT << "=1" << DELIM_FEATURE;
if (comprEnabled && isFeatureValue(headers, FEATURE_COMPR, "lz4"))
str << FEATURE_COMPR << "=lz4" << DELIM_FEATURE;
if (ledgerReplayEnabled && featureEnabled(headers, FEATURE_LEDGER_REPLAY))
@@ -414,7 +417,8 @@ makeResponse(
app.config().COMPRESSION,
app.config().LEDGER_REPLAY,
app.config().TX_REDUCE_RELAY_ENABLE,
app.config().VP_REDUCE_RELAY_ENABLE));
app.config().VP_REDUCE_RELAY_ENABLE,
app.config().LIGHT_PEERS_MAX > 0));
buildHandshake(resp, sharedValue, networkID, public_ip, remote_ip, app);

View File

@@ -146,6 +146,9 @@ static constexpr char FEATURE_VPRR[] = "vprr";
static constexpr char FEATURE_TXRR[] = "txrr";
// ledger replay
static constexpr char FEATURE_LEDGER_REPLAY[] = "ledgerreplay";
// light peer: receives validations, manifests, validator lists, ledger data,
// status and endpoints only; may only ping, request ledger data and submit
static constexpr char FEATURE_LIGHT[] = "light";
static constexpr char DELIM_FEATURE[] = ";";
static constexpr char DELIM_VALUE[] = ",";
@@ -252,7 +255,8 @@ makeFeaturesResponseHeader(
bool comprEnabled,
bool ledgerReplayEnabled,
bool txReduceRelayEnabled,
bool vpReduceRelayEnabled);
bool vpReduceRelayEnabled,
bool lightEnabled = false);
} // namespace ripple

View File

@@ -28,6 +28,7 @@ Message::Message(
int type,
std::optional<PublicKey> const& validator)
: category_(TrafficCount::categorize(message, type, false))
, type_(type)
, validatorKey_(validator)
{
using namespace ripple::compression;

View File

@@ -241,6 +241,17 @@ OverlayImpl::onHandoff(
return handoff;
}
if (featureEnabled(request, FEATURE_LIGHT) &&
lightPeerCount() >= app_.config().LIGHT_PEERS_MAX)
{
m_peerFinder->on_closed(slot);
handoff.moved = false;
handoff.response = makeErrorResponse(
slot, request, remote_endpoint.address(), "Light peer slots full");
handoff.keep_alive = false;
return handoff;
}
auto const sharedValue = makeSharedValue(*stream_ptr, journal);
if (!sharedValue)
{
@@ -1060,6 +1071,17 @@ OverlayImpl::getActivePeers() const
return ret;
}
std::size_t
OverlayImpl::lightPeerCount() const
{
std::lock_guard lock(mutex_);
std::size_t n = 0;
for (auto const& [id, w] : ids_)
if (auto const p = w.lock(); p && p->isLight())
++n;
return n;
}
Overlay::PeerSequence
OverlayImpl::getActivePeers(
std::set<Peer::id_t> const& toSkip,
@@ -1080,6 +1102,11 @@ OverlayImpl::getActivePeers(
{
if (p = w.lock(); p != nullptr)
{
if (p->isLight())
{
--active;
continue;
}
bool const reduceRelayEnabled = p->txReduceRelayEnabled();
// tx reduced relay feature disabled
if (!reduceRelayEnabled)

View File

@@ -197,6 +197,10 @@ public:
PeerSequence
getActivePeers() const override;
/** Number of connected light peers. */
std::size_t
lightPeerCount() const;
/** Get active peers excluding peers in toSkip.
@param toSkip peers to skip
@param active a number of active peers

View File

@@ -63,6 +63,49 @@ std::chrono::seconds constexpr peerTimerInterval{60};
// TODO: Remove this exclusion once unit tests are added after the hotfix
// release.
namespace {
// What a light peer may be sent: enough to follow validated ledgers and
// learn other hubs. Never proposals, transactions or tx-set traffic.
bool
lightMayReceive(int type)
{
using namespace protocol;
switch (type)
{
case mtPING:
case mtMANIFESTS:
case mtVALIDATION:
case mtVALIDATORLIST:
case mtVALIDATORLISTCOLLECTION:
case mtLEDGER_DATA:
case mtSTATUS_CHANGE:
case mtENDPOINTS:
return true;
default:
return false;
}
}
// What a light peer may send us.
bool
lightMaySend(int type)
{
using namespace protocol;
switch (type)
{
case mtPING:
case mtGET_LEDGER:
case mtTRANSACTION:
case mtLEDGER_DATA:
return true;
default:
return false;
}
}
} // namespace
PeerImp::PeerImp(
Application& app,
id_t id,
@@ -120,6 +163,10 @@ PeerImp::PeerImp(
headers_,
FEATURE_LEDGER_REPLAY,
app_.config().LEDGER_REPLAY))
, light_(peerFeatureEnabled(
headers_,
FEATURE_LIGHT,
app_.config().LIGHT_PEERS_MAX > 0))
, ledgerReplayMsgHandler_(app, app.getLedgerReplayer())
{
JLOG(journal_.info()) << "compression enabled "
@@ -247,6 +294,9 @@ PeerImp::send(std::shared_ptr<Message> const& m)
if (detaching_)
return;
if (light_ && !lightMayReceive(m->getType()))
return;
auto validator = m->getValidatorKey();
if (validator && !squelch_.expireSquelch(*validator))
return;
@@ -387,6 +437,9 @@ PeerImp::json()
if (inbound_)
ret[jss::inbound] = true;
if (light_)
ret["light"] = true;
if (cluster())
{
ret[jss::cluster] = true;
@@ -1028,6 +1081,10 @@ PeerImp::onMessageBegin(
auto const name = protocolMessageName(type);
load_event_ = app_.getJobQueue().makeLoadEvent(jtPEER, name);
fee_ = {Resource::feeTrivialPeer, name};
dropCurrent_ = light_ && !lightMaySend(type);
if (dropCurrent_)
fee_ = {
Resource::feeMalformedRequest, "light peer: disallowed message"};
auto const category = TrafficCount::categorize(*m, type, true);
overlay_.reportTraffic(category, true, static_cast<int>(size));
using namespace protocol;
@@ -3252,8 +3309,9 @@ PeerImp::getTxSet(std::shared_ptr<protocol::TMGetLedger> const& m) const
void
PeerImp::processLedgerRequest(std::shared_ptr<protocol::TMGetLedger> const& m)
{
// Do not resource charge a peer responding to a relay
if (!m->has_requestcookie())
// Do not resource charge a peer responding to a relay. Light peers never
// relay, so a cookie from one buys nothing.
if (!m->has_requestcookie() || light_)
charge(
Resource::feeModerateBurdenPeer, "received a get ledger request");

View File

@@ -194,6 +194,10 @@ private:
// on the peer.
bool vpReduceRelayEnabled_ = false;
bool ledgerReplayEnabled_ = false;
// true if this inbound peer negotiated light mode (FEATURE_LIGHT)
bool light_ = false;
// set in onMessageBegin when a light peer sent a disallowed message
bool dropCurrent_ = false;
LedgerReplayMsgHandler ledgerReplayMsgHandler_;
friend class OverlayImpl;
@@ -442,6 +446,19 @@ public:
return txReduceRelayEnabled_;
}
bool
isLight() const override
{
return light_;
}
/** Consulted by invokeProtocolMessage after onMessageBegin. */
bool
dropMessage() const
{
return dropCurrent_;
}
private:
void
close();

View File

@@ -74,6 +74,8 @@ PeerSetImpl::addPeers(
pairs.reserve(overlay.size());
overlay.foreach([&](auto const& peer) {
if (peer->isLight())
return;
auto const score = peer->getScore(hasItem(peer));
pairs.emplace_back(score, std::move(peer));
});

View File

@@ -311,6 +311,14 @@ invoke(MessageHeader const& header, Buffers const& buffers, Handler& handler)
header.payload_wire_size,
header.uncompressed_size,
header.algorithm != Algorithm::None);
if constexpr (requires { handler.dropMessage(); })
{
if (handler.dropMessage())
{
handler.onMessageEnd(header.message_type, m);
return true;
}
}
handler.onMessage(m);
handler.onMessageEnd(header.message_type, m);