mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Report escalated ledger fee in load_factor (RIPD-1207):
* Updates both server_info and server_state * Adds "load_factor_server", which reports the server-only portion of the load (if appropriate) so clients can decide an appropriate fee to pay if the open ledger fee is higher than they're willing to pay. === Release Notes === ==== Updated Features ==== Both `server_info` and `server_state` report the escalated ledger fee in the `load_factor` result parameter. If appropriate, `load_factor_server` reports the server-only portion of the load so clients can submit a fee between those two values to get into the queue.
This commit is contained in:
@@ -44,6 +44,7 @@
|
||||
#include <ripple/app/tx/apply.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/mulDiv.h>
|
||||
#include <ripple/basics/random.h>
|
||||
#include <ripple/protocol/digest.h>
|
||||
#include <ripple/basics/StringUtilities.h>
|
||||
@@ -2095,57 +2096,74 @@ Json::Value NetworkOPsImp::getServerInfo (bool human, bool admin)
|
||||
|
||||
auto const escalationMetrics = app_.getTxQ().getMetrics(
|
||||
app_.config(), *app_.openLedger().current());
|
||||
|
||||
constexpr std::uint64_t max32 =
|
||||
std::numeric_limits<std::uint32_t>::max();
|
||||
auto const loadFactorServer = app_.getFeeTrack().getLoadFactor();
|
||||
auto const loadBaseServer = app_.getFeeTrack().getLoadBase();
|
||||
auto const loadFactorFeeEscalation = escalationMetrics ?
|
||||
escalationMetrics->expFeeLevel : 1;
|
||||
auto const loadBaseFeeEscalation = escalationMetrics ?
|
||||
escalationMetrics->referenceFeeLevel : 1;
|
||||
|
||||
auto const loadFactor = std::max(static_cast<std::uint64_t>(loadFactorServer),
|
||||
mulDiv(loadFactorFeeEscalation, loadBaseServer, loadBaseFeeEscalation).second);
|
||||
|
||||
if (!human)
|
||||
{
|
||||
info[jss::load_base] = app_.getFeeTrack ().getLoadBase ();
|
||||
info[jss::load_factor] = app_.getFeeTrack ().getLoadFactor ();
|
||||
info[jss::load_base] = loadBaseServer;
|
||||
info[jss::load_factor] = static_cast<std::uint32_t>(
|
||||
std::min(max32, loadFactor));
|
||||
if (escalationMetrics)
|
||||
{
|
||||
info[jss::load_factor_server] = loadFactorServer;
|
||||
|
||||
/* Json::Value doesn't support uint64, so clamp to max
|
||||
uint32 value. This is mostly theoretical, since there
|
||||
probably isn't enough extant XRP to drive the factor
|
||||
that high.
|
||||
*/
|
||||
constexpr std::uint64_t max =
|
||||
std::numeric_limits<std::uint32_t>::max();
|
||||
info[jss::load_factor_fee_escalation] =
|
||||
static_cast<std::uint32_t> (std::min(
|
||||
max, escalationMetrics->expFeeLevel));
|
||||
max32, loadFactorFeeEscalation));
|
||||
info[jss::load_factor_fee_queue] =
|
||||
static_cast<std::uint32_t> (std::min(
|
||||
max, escalationMetrics->minFeeLevel));
|
||||
max32, escalationMetrics->minFeeLevel));
|
||||
info[jss::load_factor_fee_reference] =
|
||||
static_cast<std::uint32_t> (std::min(
|
||||
max, escalationMetrics->referenceFeeLevel));
|
||||
max32, loadBaseFeeEscalation));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
info[jss::load_factor] =
|
||||
static_cast<double> (app_.getFeeTrack ().getLoadFactor ()) /
|
||||
app_.getFeeTrack ().getLoadBase ();
|
||||
info[jss::load_factor] = static_cast<double> (loadFactor) / loadBaseServer;
|
||||
|
||||
if (loadFactorServer != loadFactor)
|
||||
info[jss::load_factor_server] =
|
||||
static_cast<double> (loadFactorServer) / loadBaseServer;
|
||||
|
||||
if (admin)
|
||||
{
|
||||
std::uint32_t base = app_.getFeeTrack().getLoadBase();
|
||||
std::uint32_t fee = app_.getFeeTrack().getLocalFee();
|
||||
if (fee != base)
|
||||
if (fee != loadBaseServer)
|
||||
info[jss::load_factor_local] =
|
||||
static_cast<double> (fee) / base;
|
||||
static_cast<double> (fee) / loadBaseServer;
|
||||
fee = app_.getFeeTrack ().getRemoteFee();
|
||||
if (fee != base)
|
||||
if (fee != loadBaseServer)
|
||||
info[jss::load_factor_net] =
|
||||
static_cast<double> (fee) / base;
|
||||
static_cast<double> (fee) / loadBaseServer;
|
||||
fee = app_.getFeeTrack().getClusterFee();
|
||||
if (fee != base)
|
||||
if (fee != loadBaseServer)
|
||||
info[jss::load_factor_cluster] =
|
||||
static_cast<double> (fee) / base;
|
||||
static_cast<double> (fee) / loadBaseServer;
|
||||
}
|
||||
if (escalationMetrics)
|
||||
{
|
||||
if (escalationMetrics->expFeeLevel !=
|
||||
escalationMetrics->referenceFeeLevel)
|
||||
if (loadFactorFeeEscalation !=
|
||||
escalationMetrics->referenceFeeLevel &&
|
||||
(admin || loadFactorFeeEscalation != loadFactor))
|
||||
info[jss::load_factor_fee_escalation] =
|
||||
static_cast<double> (escalationMetrics->expFeeLevel) /
|
||||
static_cast<double> (loadFactorFeeEscalation) /
|
||||
escalationMetrics->referenceFeeLevel;
|
||||
if (escalationMetrics->minFeeLevel !=
|
||||
escalationMetrics->referenceFeeLevel)
|
||||
|
||||
@@ -2171,6 +2171,233 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void testServerInfo()
|
||||
{
|
||||
using namespace jtx;
|
||||
Env env(*this, makeConfig({ { "minimum_txn_in_ledger_standalone", "3" } }),
|
||||
features(featureFeeEscalation));
|
||||
Env_ss envs(env);
|
||||
|
||||
Account const alice{ "alice" };
|
||||
env.fund(XRP(1000000), alice);
|
||||
env.close();
|
||||
|
||||
auto submitParams = Json::Value(Json::objectValue);
|
||||
// Max fee = 100 drops
|
||||
submitParams[jss::fee_mult_max] = 10;
|
||||
submitParams["x-queue-okay"] = true;
|
||||
submitParams["x_queue_okay"] = true;
|
||||
|
||||
{
|
||||
auto const server_info = env.rpc("server_info");
|
||||
BEAST_EXPECT(server_info.isMember(jss::result) &&
|
||||
server_info[jss::result].isMember(jss::info));
|
||||
auto const& info = server_info[jss::result][jss::info];
|
||||
BEAST_EXPECT(info.isMember(jss::load_factor) &&
|
||||
info[jss::load_factor] == 1);
|
||||
BEAST_EXPECT(!info.isMember(jss::load_factor_server));
|
||||
BEAST_EXPECT(!info.isMember(jss::load_factor_local));
|
||||
BEAST_EXPECT(!info.isMember(jss::load_factor_net));
|
||||
BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
|
||||
}
|
||||
{
|
||||
auto const server_state = env.rpc("server_state");
|
||||
log << server_state;
|
||||
auto const& state = server_state[jss::result][jss::state];
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor) &&
|
||||
state[jss::load_factor] == 256);
|
||||
BEAST_EXPECT(state.isMember(jss::load_base) &&
|
||||
state[jss::load_base] == 256);
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor_server) &&
|
||||
state[jss::load_factor_server] == 256);
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor_fee_escalation) &&
|
||||
state[jss::load_factor_fee_escalation] == 256);
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor_fee_queue) &&
|
||||
state[jss::load_factor_fee_queue] == 256);
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor_fee_reference) &&
|
||||
state[jss::load_factor_fee_reference] == 256);
|
||||
}
|
||||
|
||||
checkMetrics(env, 0, 6, 0, 3, 256);
|
||||
|
||||
fillQueue(env, alice);
|
||||
checkMetrics(env, 0, 6, 4, 3, 256);
|
||||
|
||||
auto aliceSeq = env.seq(alice);
|
||||
for (auto i = 0; i < 4; ++i)
|
||||
envs(noop(alice), fee(none), seq(aliceSeq + i),
|
||||
ter(terQUEUED))(submitParams);
|
||||
checkMetrics(env, 4, 6, 4, 3, 256);
|
||||
|
||||
{
|
||||
auto const server_info = env.rpc("server_info");
|
||||
BEAST_EXPECT(server_info.isMember(jss::result) &&
|
||||
server_info[jss::result].isMember(jss::info));
|
||||
auto const& info = server_info[jss::result][jss::info];
|
||||
// Avoid double rounding issues by comparing to a range.
|
||||
BEAST_EXPECT(info.isMember(jss::load_factor) &&
|
||||
info[jss::load_factor] > 888.88 &&
|
||||
info[jss::load_factor] < 888.89);
|
||||
BEAST_EXPECT(info.isMember(jss::load_factor_server) &&
|
||||
info[jss::load_factor_server] == 1);
|
||||
BEAST_EXPECT(!info.isMember(jss::load_factor_local));
|
||||
BEAST_EXPECT(!info.isMember(jss::load_factor_net));
|
||||
BEAST_EXPECT(info.isMember(jss::load_factor_fee_escalation) &&
|
||||
info[jss::load_factor_fee_escalation] > 888.88 &&
|
||||
info[jss::load_factor_fee_escalation] < 888.89);
|
||||
}
|
||||
{
|
||||
auto const server_state = env.rpc("server_state");
|
||||
log << server_state;
|
||||
auto const& state = server_state[jss::result][jss::state];
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor) &&
|
||||
state[jss::load_factor] == 227555);
|
||||
BEAST_EXPECT(state.isMember(jss::load_base) &&
|
||||
state[jss::load_base] == 256);
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor_server) &&
|
||||
state[jss::load_factor_server] == 256);
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor_fee_escalation) &&
|
||||
state[jss::load_factor_fee_escalation] == 227555);
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor_fee_queue) &&
|
||||
state[jss::load_factor_fee_queue] == 256);
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor_fee_reference) &&
|
||||
state[jss::load_factor_fee_reference] == 256);
|
||||
}
|
||||
|
||||
env.app().getFeeTrack().setRemoteFee(256000);
|
||||
|
||||
{
|
||||
auto const server_info = env.rpc("server_info");
|
||||
BEAST_EXPECT(server_info.isMember(jss::result) &&
|
||||
server_info[jss::result].isMember(jss::info));
|
||||
auto const& info = server_info[jss::result][jss::info];
|
||||
// Avoid double rounding issues by comparing to a range.
|
||||
BEAST_EXPECT(info.isMember(jss::load_factor) &&
|
||||
info[jss::load_factor] == 1000);
|
||||
BEAST_EXPECT(!info.isMember(jss::load_factor_server));
|
||||
BEAST_EXPECT(!info.isMember(jss::load_factor_local));
|
||||
BEAST_EXPECT(info.isMember(jss::load_factor_net) &&
|
||||
info[jss::load_factor_net] == 1000);
|
||||
BEAST_EXPECT(info.isMember(jss::load_factor_fee_escalation) &&
|
||||
info[jss::load_factor_fee_escalation] > 888.88 &&
|
||||
info[jss::load_factor_fee_escalation] < 888.89);
|
||||
}
|
||||
{
|
||||
auto const server_state = env.rpc("server_state");
|
||||
log << server_state;
|
||||
auto const& state = server_state[jss::result][jss::state];
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor) &&
|
||||
state[jss::load_factor] == 256000);
|
||||
BEAST_EXPECT(state.isMember(jss::load_base) &&
|
||||
state[jss::load_base] == 256);
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor_server) &&
|
||||
state[jss::load_factor_server] == 256000);
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor_fee_escalation) &&
|
||||
state[jss::load_factor_fee_escalation] == 227555);
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor_fee_queue) &&
|
||||
state[jss::load_factor_fee_queue] == 256);
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor_fee_reference) &&
|
||||
state[jss::load_factor_fee_reference] == 256);
|
||||
}
|
||||
|
||||
env.app().getFeeTrack().setRemoteFee(256);
|
||||
|
||||
// Increase the server load
|
||||
for (int i = 0; i < 5; ++i)
|
||||
env.app().getFeeTrack().raiseLocalFee();
|
||||
BEAST_EXPECT(env.app().getFeeTrack().getLoadFactor() == 625);
|
||||
|
||||
{
|
||||
auto const server_info = env.rpc("server_info");
|
||||
BEAST_EXPECT(server_info.isMember(jss::result) &&
|
||||
server_info[jss::result].isMember(jss::info));
|
||||
auto const& info = server_info[jss::result][jss::info];
|
||||
// Avoid double rounding issues by comparing to a range.
|
||||
BEAST_EXPECT(info.isMember(jss::load_factor) &&
|
||||
info[jss::load_factor] > 888.88 &&
|
||||
info[jss::load_factor] < 888.89);
|
||||
// There can be a race between LoadManager lowering the fee,
|
||||
// and the call to server_info, so check a wide range.
|
||||
// The important thing is that it's not 1.
|
||||
BEAST_EXPECT(info.isMember(jss::load_factor_server) &&
|
||||
info[jss::load_factor_server] > 1.245 &&
|
||||
info[jss::load_factor_server] < 2.4415);
|
||||
BEAST_EXPECT(info.isMember(jss::load_factor_local) &&
|
||||
info[jss::load_factor_local] > 1.245 &&
|
||||
info[jss::load_factor_local] < 2.4415);
|
||||
BEAST_EXPECT(!info.isMember(jss::load_factor_net));
|
||||
BEAST_EXPECT(info.isMember(jss::load_factor_fee_escalation) &&
|
||||
info[jss::load_factor_fee_escalation] > 888.88 &&
|
||||
info[jss::load_factor_fee_escalation] < 888.89);
|
||||
}
|
||||
{
|
||||
auto const server_state = env.rpc("server_state");
|
||||
log << server_state;
|
||||
auto const& state = server_state[jss::result][jss::state];
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor) &&
|
||||
state[jss::load_factor] == 227555);
|
||||
BEAST_EXPECT(state.isMember(jss::load_base) &&
|
||||
state[jss::load_base] == 256);
|
||||
// There can be a race between LoadManager lowering the fee,
|
||||
// and the call to server_info, so check a wide range.
|
||||
// The important thing is that it's not 256.
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor_server) &&
|
||||
state[jss::load_factor_server] >= 320 &&
|
||||
state[jss::load_factor_server] <= 625);
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor_fee_escalation) &&
|
||||
state[jss::load_factor_fee_escalation] == 227555);
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor_fee_queue) &&
|
||||
state[jss::load_factor_fee_queue] == 256);
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor_fee_reference) &&
|
||||
state[jss::load_factor_fee_reference] == 256);
|
||||
}
|
||||
|
||||
env.close();
|
||||
|
||||
{
|
||||
auto const server_info = env.rpc("server_info");
|
||||
BEAST_EXPECT(server_info.isMember(jss::result) &&
|
||||
server_info[jss::result].isMember(jss::info));
|
||||
auto const& info = server_info[jss::result][jss::info];
|
||||
// Avoid double rounding issues by comparing to a range.
|
||||
|
||||
// There can be a race between LoadManager lowering the fee,
|
||||
// and the call to server_info, so check a wide range.
|
||||
// The important thing is that it's not 1.
|
||||
BEAST_EXPECT(info.isMember(jss::load_factor) &&
|
||||
info[jss::load_factor] > 1.245 &&
|
||||
info[jss::load_factor] < 2.4415);
|
||||
BEAST_EXPECT(!info.isMember(jss::load_factor_server));
|
||||
BEAST_EXPECT(info.isMember(jss::load_factor_local) &&
|
||||
info[jss::load_factor_local] > 1.245 &&
|
||||
info[jss::load_factor_local] < 2.4415);
|
||||
BEAST_EXPECT(!info.isMember(jss::load_factor_net));
|
||||
BEAST_EXPECT(!info.isMember(jss::load_factor_fee_escalation));
|
||||
}
|
||||
{
|
||||
auto const server_state = env.rpc("server_state");
|
||||
log << server_state;
|
||||
auto const& state = server_state[jss::result][jss::state];
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor) &&
|
||||
state[jss::load_factor] >= 320 &&
|
||||
state[jss::load_factor] <= 625);
|
||||
BEAST_EXPECT(state.isMember(jss::load_base) &&
|
||||
state[jss::load_base] == 256);
|
||||
// There can be a race between LoadManager lowering the fee,
|
||||
// and the call to server_info, so check a wide range.
|
||||
// The important thing is that it's not 256.
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor_server) &&
|
||||
state[jss::load_factor_server] >= 320 &&
|
||||
state[jss::load_factor_server] <= 625);
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor_fee_escalation) &&
|
||||
state[jss::load_factor_fee_escalation] == 256);
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor_fee_queue) &&
|
||||
state[jss::load_factor_fee_queue] == 256);
|
||||
BEAST_EXPECT(state.isMember(jss::load_factor_fee_reference) &&
|
||||
state[jss::load_factor_fee_reference] == 256);
|
||||
}
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
testQueue();
|
||||
@@ -2192,6 +2419,7 @@ public:
|
||||
testExpirationReplacement();
|
||||
testSignAndSubmitSequence();
|
||||
testAccountInfo();
|
||||
testServerInfo();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -244,6 +244,7 @@ JSS ( load_factor_fee_queue ); // out: NetworkOPs
|
||||
JSS ( load_factor_fee_reference ); // out: NetworkOPs
|
||||
JSS ( load_factor_local ); // out: NetworkOPs
|
||||
JSS ( load_factor_net ); // out: NetworkOPs
|
||||
JSS ( load_factor_server ); // out: NetworkOPs
|
||||
JSS ( load_fee ); // out: LoadFeeTrackImp, NetworkOPs
|
||||
JSS ( local ); // out: resource/Logic.h
|
||||
JSS ( local_txs ); // out: GetCounts
|
||||
|
||||
Reference in New Issue
Block a user