mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Minor refactor of LoadFeeTrack (RIPD-956):
* Load scaling functions are free, and take `Fees`. * Move LoadFeeTrack to app/misc. * Update naming convention.
This commit is contained in:
@@ -1,139 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_CORE_LOADFEETRACK_H_INCLUDED
|
||||
#define RIPPLE_CORE_LOADFEETRACK_H_INCLUDED
|
||||
|
||||
#include <ripple/json/json_value.h>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** Manages the current fee schedule.
|
||||
|
||||
The "base" fee is the cost to send a reference transaction under no load,
|
||||
expressed in millionths of one XRP.
|
||||
|
||||
The "load" fee is how much the local server currently charges to send a
|
||||
reference transaction. This fee fluctuates based on the load of the
|
||||
server.
|
||||
*/
|
||||
// VFALCO TODO Rename "load" to "current".
|
||||
class LoadFeeTrack
|
||||
{
|
||||
public:
|
||||
explicit LoadFeeTrack (beast::Journal journal = beast::Journal())
|
||||
: m_journal (journal)
|
||||
, mLocalTxnLoadFee (lftNormalFee)
|
||||
, mRemoteTxnLoadFee (lftNormalFee)
|
||||
, mClusterTxnLoadFee (lftNormalFee)
|
||||
, raiseCount (0)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~LoadFeeTrack () { }
|
||||
|
||||
// Scale from fee units to millionths of a ripple
|
||||
std::uint64_t scaleFeeBase (std::uint64_t fee, std::uint64_t baseFee,
|
||||
std::uint32_t referenceFeeUnits) const;
|
||||
|
||||
// Scale using load as well as base rate
|
||||
std::uint64_t scaleFeeLoad (std::uint64_t fee, std::uint64_t baseFee,
|
||||
std::uint32_t referenceFeeUnits, bool bUnlimited) const;
|
||||
|
||||
void setRemoteFee (std::uint32_t f)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
mRemoteTxnLoadFee = f;
|
||||
}
|
||||
|
||||
std::uint32_t getRemoteFee () const
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
return mRemoteTxnLoadFee;
|
||||
}
|
||||
|
||||
std::uint32_t getLocalFee () const
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
return mLocalTxnLoadFee;
|
||||
}
|
||||
|
||||
std::uint32_t getClusterFee () const
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
return mClusterTxnLoadFee;
|
||||
}
|
||||
|
||||
std::uint32_t getLoadBase () const
|
||||
{
|
||||
return lftNormalFee;
|
||||
}
|
||||
|
||||
std::uint32_t getLoadFactor () const
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
return std::max({ mClusterTxnLoadFee, mLocalTxnLoadFee, mRemoteTxnLoadFee });
|
||||
}
|
||||
|
||||
|
||||
void setClusterFee (std::uint32_t fee)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
mClusterTxnLoadFee = fee;
|
||||
}
|
||||
|
||||
bool raiseLocalFee ();
|
||||
bool lowerLocalFee ();
|
||||
|
||||
bool isLoadedLocal () const
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
return (raiseCount != 0) || (mLocalTxnLoadFee != lftNormalFee);
|
||||
}
|
||||
|
||||
bool isLoadedCluster () const
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
return (raiseCount != 0) || (mLocalTxnLoadFee != lftNormalFee) || (mClusterTxnLoadFee != lftNormalFee);
|
||||
}
|
||||
|
||||
private:
|
||||
static const int lftNormalFee = 256; // 256 is the minimum/normal load factor
|
||||
static const int lftFeeIncFraction = 4; // increase fee by 1/4
|
||||
static const int lftFeeDecFraction = 4; // decrease fee by 1/4
|
||||
static const int lftFeeMax = lftNormalFee * 1000000;
|
||||
|
||||
beast::Journal m_journal;
|
||||
using LockType = std::mutex;
|
||||
using ScopedLockType = std::lock_guard <LockType>;
|
||||
LockType mutable mLock;
|
||||
|
||||
std::uint32_t mLocalTxnLoadFee; // Scale factor, lftNormalFee = normal fee
|
||||
std::uint32_t mRemoteTxnLoadFee; // Scale factor, lftNormalFee = normal fee
|
||||
std::uint32_t mClusterTxnLoadFee; // Scale factor, lftNormalFee = normal fee
|
||||
int raiseCount;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
|
||||
#endif
|
||||
@@ -1,154 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/mulDiv.h>
|
||||
#include <ripple/core/LoadFeeTrack.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/protocol/STAmount.h>
|
||||
#include <ripple/protocol/JsonFields.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// Scale from fee units to millionths of a ripple
|
||||
std::uint64_t
|
||||
LoadFeeTrack::scaleFeeBase (std::uint64_t fee, std::uint64_t baseFee,
|
||||
std::uint32_t referenceFeeUnits) const
|
||||
{
|
||||
return mulDivThrow (fee, baseFee, referenceFeeUnits);
|
||||
}
|
||||
|
||||
// Scale using load as well as base rate
|
||||
std::uint64_t
|
||||
LoadFeeTrack::scaleFeeLoad (std::uint64_t fee, std::uint64_t baseFee,
|
||||
std::uint32_t referenceFeeUnits, bool bUnlimited) const
|
||||
{
|
||||
if (fee == 0)
|
||||
return fee;
|
||||
std::uint32_t feeFactor;
|
||||
std::uint32_t uRemFee;
|
||||
{
|
||||
// Collect the fee rates
|
||||
std::lock_guard<std::mutex> sl(mLock);
|
||||
feeFactor = std::max(mLocalTxnLoadFee, mRemoteTxnLoadFee);
|
||||
uRemFee = std::max(mRemoteTxnLoadFee, mClusterTxnLoadFee);
|
||||
}
|
||||
// Let privileged users pay the normal fee until
|
||||
// the local load exceeds four times the remote.
|
||||
if (bUnlimited && (feeFactor > uRemFee) && (feeFactor < (4 * uRemFee)))
|
||||
feeFactor = uRemFee;
|
||||
|
||||
// Compute:
|
||||
// fee = fee * baseFee * feeFactor / (referenceFeeUnits * lftNormalFee);
|
||||
// without overflow, and as accurately as possible
|
||||
|
||||
// The denominator of the fraction we're trying to compute.
|
||||
// referenceFeeUnits and lftNormalFee are both 32 bit,
|
||||
// so the multiplication can't overflow.
|
||||
auto den = static_cast<std::uint64_t>(referenceFeeUnits)
|
||||
* static_cast<std::uint64_t>(lftNormalFee);
|
||||
// Reduce fee * baseFee * feeFactor / (referenceFeeUnits * lftNormalFee)
|
||||
// to lowest terms.
|
||||
lowestTerms(fee, den);
|
||||
lowestTerms(baseFee, den);
|
||||
lowestTerms(feeFactor, den);
|
||||
|
||||
// fee and baseFee are 64 bit, feeFactor is 32 bit
|
||||
// Order fee and baseFee largest first
|
||||
if (fee < baseFee)
|
||||
std::swap(fee, baseFee);
|
||||
// If baseFee * feeFactor overflows, the final result will overflow
|
||||
const auto max = std::numeric_limits<std::uint64_t>::max();
|
||||
if (baseFee > max / feeFactor)
|
||||
Throw<std::overflow_error> ("scaleFeeLoad");
|
||||
baseFee *= feeFactor;
|
||||
// Reorder fee and baseFee
|
||||
if (fee < baseFee)
|
||||
std::swap(fee, baseFee);
|
||||
// If fee * baseFee / den might overflow...
|
||||
if (fee > max / baseFee)
|
||||
{
|
||||
// Do the division first, on the larger of fee and baseFee
|
||||
fee /= den;
|
||||
if (fee > max / baseFee)
|
||||
Throw<std::overflow_error> ("scaleFeeLoad");
|
||||
fee *= baseFee;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise fee * baseFee won't overflow,
|
||||
// so do it prior to the division.
|
||||
fee *= baseFee;
|
||||
fee /= den;
|
||||
}
|
||||
return fee;
|
||||
}
|
||||
|
||||
bool
|
||||
LoadFeeTrack::raiseLocalFee ()
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
|
||||
if (++raiseCount < 2)
|
||||
return false;
|
||||
|
||||
std::uint32_t origFee = mLocalTxnLoadFee;
|
||||
|
||||
// make sure this fee takes effect
|
||||
if (mLocalTxnLoadFee < mRemoteTxnLoadFee)
|
||||
mLocalTxnLoadFee = mRemoteTxnLoadFee;
|
||||
|
||||
// Increase slowly
|
||||
mLocalTxnLoadFee += (mLocalTxnLoadFee / lftFeeIncFraction);
|
||||
|
||||
if (mLocalTxnLoadFee > lftFeeMax)
|
||||
mLocalTxnLoadFee = lftFeeMax;
|
||||
|
||||
if (origFee == mLocalTxnLoadFee)
|
||||
return false;
|
||||
|
||||
JLOG(m_journal.debug()) << "Local load fee raised from " <<
|
||||
origFee << " to " << mLocalTxnLoadFee;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
LoadFeeTrack::lowerLocalFee ()
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
std::uint32_t origFee = mLocalTxnLoadFee;
|
||||
raiseCount = 0;
|
||||
|
||||
// Reduce slowly
|
||||
mLocalTxnLoadFee -= (mLocalTxnLoadFee / lftFeeDecFraction );
|
||||
|
||||
if (mLocalTxnLoadFee < lftNormalFee)
|
||||
mLocalTxnLoadFee = lftNormalFee;
|
||||
|
||||
if (origFee == mLocalTxnLoadFee)
|
||||
return false;
|
||||
|
||||
JLOG(m_journal.debug()) << "Local load fee lowered from " <<
|
||||
origFee << " to " << mLocalTxnLoadFee;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // ripple
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/core/LoadFeeTrack.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/core/ConfigSections.h>
|
||||
#include <ripple/basics/TestSuite.h>
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/core/LoadFeeTrack.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/beast/unit_test.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class LoadFeeTrack_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
void run ()
|
||||
{
|
||||
Config d; // get a default configuration object
|
||||
LoadFeeTrack l;
|
||||
|
||||
BEAST_EXPECT(l.scaleFeeBase (10000, d.FEE_DEFAULT, d.TRANSACTION_FEE_BASE) == 10000);
|
||||
BEAST_EXPECT(l.scaleFeeLoad (10000, d.FEE_DEFAULT, d.TRANSACTION_FEE_BASE, false) == 10000);
|
||||
BEAST_EXPECT(l.scaleFeeBase (1, d.FEE_DEFAULT, d.TRANSACTION_FEE_BASE) == 1);
|
||||
BEAST_EXPECT(l.scaleFeeLoad (1, d.FEE_DEFAULT, d.TRANSACTION_FEE_BASE, false) == 1);
|
||||
|
||||
// Check new default fee values give same fees as old defaults
|
||||
BEAST_EXPECT(l.scaleFeeBase (d.FEE_DEFAULT, d.FEE_DEFAULT, d.TRANSACTION_FEE_BASE) == 10);
|
||||
BEAST_EXPECT(l.scaleFeeBase (d.FEE_ACCOUNT_RESERVE, d.FEE_DEFAULT, d.TRANSACTION_FEE_BASE) == 200 * SYSTEM_CURRENCY_PARTS);
|
||||
BEAST_EXPECT(l.scaleFeeBase (d.FEE_OWNER_RESERVE, d.FEE_DEFAULT, d.TRANSACTION_FEE_BASE) == 50 * SYSTEM_CURRENCY_PARTS);
|
||||
BEAST_EXPECT(l.scaleFeeBase (d.FEE_OFFER, d.FEE_DEFAULT, d.TRANSACTION_FEE_BASE) == 10);
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(LoadFeeTrack,ripple_core,ripple);
|
||||
|
||||
} // ripple
|
||||
Reference in New Issue
Block a user