mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Add fee voting configuration and docs (RIPD-564)
This commit is contained in:
@@ -22,6 +22,8 @@
|
||||
#
|
||||
# 8. Diagnostics
|
||||
#
|
||||
# 9. Voting
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# Purpose
|
||||
@@ -770,6 +772,57 @@
|
||||
# prefix=my_validator
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 9. Voting
|
||||
#
|
||||
#----------
|
||||
#
|
||||
# The vote settings configure settings for the entire Ripple network.
|
||||
# While a single instance of rippled cannot unilaterally enforce network-wide
|
||||
# settings, these choices become part of the instance's vote during the
|
||||
# consensus process for each voting ledger.
|
||||
#
|
||||
# [voting]
|
||||
#
|
||||
# A set of key/value pair parameters used during voting ledgers.
|
||||
#
|
||||
# reference_fee = <drops>
|
||||
#
|
||||
# The cost of the reference transaction fee, specified in drops.
|
||||
# The reference transaction is the simplest form of transaction.
|
||||
# It represents an XRP payment between two parties.
|
||||
#
|
||||
# If this parameter is unspecified, rippled will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# reference_fee = 10 # 10 drops
|
||||
#
|
||||
# account_reserve = <drops>
|
||||
#
|
||||
# The account reserve requirement specified in drops. The portion of an
|
||||
# account's XRP balance that is at or below the reserve may only be
|
||||
# spent on transaction fees, and not transferred out of the account.
|
||||
#
|
||||
# If this parameter is unspecified, rippled will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# account_reserve = 20000000 # 20 XRP
|
||||
#
|
||||
# owner_reserve = <drops>
|
||||
#
|
||||
# The owner reserve is the amount of XRP reserved in the account for
|
||||
# each ledger item owned by the account. Ledger items an account may
|
||||
# own include trust lines, open orders, and tickets.
|
||||
#
|
||||
# If this parameter is unspecified, rippled will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# owner_reserve = 5000000 # 5 XRP
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# Allow other peers to connect to this server.
|
||||
#
|
||||
|
||||
@@ -17,8 +17,11 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_IFEEVOTE_H
|
||||
#define RIPPLE_IFEEVOTE_H
|
||||
#ifndef RIPPLE_APP_FEEVOTE_H_INCLUDED
|
||||
#define RIPPLE_APP_FEEVOTE_H_INCLUDED
|
||||
|
||||
#include <ripple/core/Section.h>
|
||||
#include <ripple/core/SystemParameters.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -26,22 +29,33 @@ namespace ripple {
|
||||
class FeeVote
|
||||
{
|
||||
public:
|
||||
/** Create a new fee vote manager.
|
||||
|
||||
@param targetBaseFee
|
||||
@param targetReserveBase
|
||||
@param targetReserveIncrement
|
||||
@param journal
|
||||
/** Fee schedule to vote for.
|
||||
During voting ledgers, the FeeVote logic will try to move towards
|
||||
these values when injecting fee-setting transactions.
|
||||
A default-constructed Setup contains recommended values.
|
||||
*/
|
||||
struct Setup
|
||||
{
|
||||
/** The cost of a reference transaction in drops. */
|
||||
std::uint64_t reference_fee = 10;
|
||||
|
||||
virtual ~FeeVote () { }
|
||||
/** The account reserve requirement in drops. */
|
||||
std::uint64_t account_reserve = 20 * SYSTEM_CURRENCY_PARTS;
|
||||
|
||||
/** The per-owned item reserve requirement in drops. */
|
||||
std::uint64_t owner_reserve = 5 * SYSTEM_CURRENCY_PARTS;
|
||||
};
|
||||
|
||||
virtual ~FeeVote () = default;
|
||||
|
||||
/** Add local fee preference to validation.
|
||||
|
||||
@param lastClosedLedger
|
||||
@param baseValidation
|
||||
*/
|
||||
virtual void doValidation (Ledger::ref lastClosedLedger,
|
||||
virtual
|
||||
void
|
||||
doValidation (Ledger::ref lastClosedLedger,
|
||||
STObject& baseValidation) = 0;
|
||||
|
||||
/** Cast our local vote on the fee.
|
||||
@@ -49,13 +63,22 @@ public:
|
||||
@param lastClosedLedger
|
||||
@param initialPosition
|
||||
*/
|
||||
virtual void doVoting (Ledger::ref lastClosedLedger,
|
||||
virtual
|
||||
void
|
||||
doVoting (Ledger::ref lastClosedLedger,
|
||||
SHAMap::ref initialPosition) = 0;
|
||||
};
|
||||
|
||||
/** Build FeeVote::Setup from a config section. */
|
||||
FeeVote::Setup
|
||||
setup_FeeVote (Section const& section);
|
||||
|
||||
/** Create an instance of the FeeVote logic.
|
||||
@param setup The fee schedule to vote for.
|
||||
@param journal Where to log.
|
||||
*/
|
||||
std::unique_ptr <FeeVote>
|
||||
make_FeeVote (std::uint64_t targetBaseFee, std::uint32_t targetReserveBase,
|
||||
std::uint32_t targetReserveIncrement, beast::Journal journal);
|
||||
make_FeeVote (FeeVote::Setup const& setup, beast::Journal journal);
|
||||
|
||||
} // ripple
|
||||
|
||||
|
||||
@@ -19,15 +19,17 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class FeaturesImpl;
|
||||
|
||||
class FeeVoteImpl : public FeeVote
|
||||
{
|
||||
private:
|
||||
namespace detail {
|
||||
|
||||
template <typename Integer>
|
||||
class VotableInteger
|
||||
{
|
||||
private:
|
||||
typedef std::map <Integer, int> map_type;
|
||||
Integer mCurrent; // The current setting
|
||||
Integer mTarget; // The setting we want
|
||||
map_type mVoteMap;
|
||||
|
||||
public:
|
||||
VotableInteger (Integer current, Integer target)
|
||||
: mCurrent (current)
|
||||
@@ -37,13 +39,6 @@ private:
|
||||
++mVoteMap[mTarget];
|
||||
}
|
||||
|
||||
bool
|
||||
mayVote () const
|
||||
{
|
||||
// If we love the current setting, we will not vote
|
||||
return mCurrent != mTarget;
|
||||
}
|
||||
|
||||
void
|
||||
addVote(Integer vote)
|
||||
{
|
||||
@@ -57,12 +52,15 @@ private:
|
||||
}
|
||||
|
||||
Integer
|
||||
getVotes ()
|
||||
getVotes() const;
|
||||
};
|
||||
|
||||
template <class Integer>
|
||||
Integer
|
||||
VotableInteger <Integer>::getVotes() const
|
||||
{
|
||||
Integer ourVote = mCurrent;
|
||||
int weight = 0;
|
||||
|
||||
typedef typename std::map<Integer, int>::value_type mapVType;
|
||||
for (auto const& e : mVoteMap)
|
||||
{
|
||||
// Take most voted value between current and target, inclusive
|
||||
@@ -78,66 +76,86 @@ private:
|
||||
return ourVote;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class FeeVoteImpl : public FeeVote
|
||||
{
|
||||
private:
|
||||
Integer mCurrent; // The current setting
|
||||
Integer mTarget; // The setting we want
|
||||
std::map<Integer, int> mVoteMap;
|
||||
};
|
||||
Setup target_;
|
||||
beast::Journal journal_;
|
||||
|
||||
public:
|
||||
FeeVoteImpl (std::uint64_t targetBaseFee, std::uint32_t targetReserveBase,
|
||||
std::uint32_t targetReserveIncrement, beast::Journal journal)
|
||||
: mTargetBaseFee (targetBaseFee)
|
||||
, mTargetReserveBase (targetReserveBase)
|
||||
, mTargetReserveIncrement (targetReserveIncrement)
|
||||
, m_journal (journal)
|
||||
{
|
||||
}
|
||||
FeeVoteImpl (Setup const& setup, beast::Journal journal);
|
||||
|
||||
void
|
||||
doValidation (Ledger::ref lastClosedLedger,
|
||||
STObject& baseValidation) override;
|
||||
|
||||
void
|
||||
doVoting (Ledger::ref lastClosedLedger,
|
||||
SHAMap::ref initialPosition) override;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
doValidation (Ledger::ref lastClosedLedger, STObject& baseValidation) override
|
||||
FeeVoteImpl::FeeVoteImpl (Setup const& setup, beast::Journal journal)
|
||||
: target_ (setup)
|
||||
, journal_ (journal)
|
||||
{
|
||||
if (lastClosedLedger->getBaseFee () != mTargetBaseFee)
|
||||
{
|
||||
if (m_journal.info) m_journal.info <<
|
||||
"Voting for base fee of " << mTargetBaseFee;
|
||||
|
||||
baseValidation.setFieldU64 (sfBaseFee, mTargetBaseFee);
|
||||
}
|
||||
|
||||
if (lastClosedLedger->getReserve (0) != mTargetReserveBase)
|
||||
{
|
||||
if (m_journal.info) m_journal.info <<
|
||||
"Voting for base resrve of " << mTargetReserveBase;
|
||||
|
||||
baseValidation.setFieldU32(sfReserveBase, mTargetReserveBase);
|
||||
}
|
||||
|
||||
if (lastClosedLedger->getReserveInc () != mTargetReserveIncrement)
|
||||
{
|
||||
if (m_journal.info) m_journal.info <<
|
||||
"Voting for reserve increment of " << mTargetReserveIncrement;
|
||||
|
||||
baseValidation.setFieldU32 (sfReserveIncrement, mTargetReserveIncrement);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition) override
|
||||
FeeVoteImpl::doValidation (Ledger::ref lastClosedLedger,
|
||||
STObject& baseValidation)
|
||||
{
|
||||
if (lastClosedLedger->getBaseFee () != target_.reference_fee)
|
||||
{
|
||||
if (journal_.info) journal_.info <<
|
||||
"Voting for base fee of " << target_.reference_fee;
|
||||
|
||||
baseValidation.setFieldU64 (sfBaseFee, target_.reference_fee);
|
||||
}
|
||||
|
||||
if (lastClosedLedger->getReserve (0) != target_.account_reserve)
|
||||
{
|
||||
if (journal_.info) journal_.info <<
|
||||
"Voting for base resrve of " << target_.account_reserve;
|
||||
|
||||
baseValidation.setFieldU32(sfReserveBase, target_.account_reserve);
|
||||
}
|
||||
|
||||
if (lastClosedLedger->getReserveInc () != target_.owner_reserve)
|
||||
{
|
||||
if (journal_.info) journal_.info <<
|
||||
"Voting for reserve increment of " << target_.owner_reserve;
|
||||
|
||||
baseValidation.setFieldU32 (sfReserveIncrement,
|
||||
target_.owner_reserve);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FeeVoteImpl::doVoting (Ledger::ref lastClosedLedger,
|
||||
SHAMap::ref initialPosition)
|
||||
{
|
||||
// LCL must be flag ledger
|
||||
assert ((lastClosedLedger->getLedgerSeq () % 256) == 0);
|
||||
|
||||
VotableInteger<std::uint64_t> baseFeeVote (lastClosedLedger->getBaseFee (), mTargetBaseFee);
|
||||
VotableInteger<std::uint32_t> baseReserveVote (lastClosedLedger->getReserve (0), mTargetReserveBase);
|
||||
VotableInteger<std::uint32_t> incReserveVote (lastClosedLedger->getReserveInc (), mTargetReserveIncrement);
|
||||
detail::VotableInteger<std::uint64_t> baseFeeVote (
|
||||
lastClosedLedger->getBaseFee (), target_.reference_fee);
|
||||
|
||||
detail::VotableInteger<std::uint32_t> baseReserveVote (
|
||||
lastClosedLedger->getReserve (0), target_.account_reserve);
|
||||
|
||||
detail::VotableInteger<std::uint32_t> incReserveVote (
|
||||
lastClosedLedger->getReserveInc (), target_.owner_reserve);
|
||||
|
||||
// get validations for ledger before flag
|
||||
ValidationSet set = getApp().getValidations ().getValidations (lastClosedLedger->getParentHash ());
|
||||
ValidationSet const set =
|
||||
getApp().getValidations ().getValidations (
|
||||
lastClosedLedger->getParentHash ());
|
||||
for (auto const& e : set)
|
||||
{
|
||||
SerializedValidation const& val = *e.second;
|
||||
@@ -174,16 +192,16 @@ public:
|
||||
}
|
||||
|
||||
// choose our positions
|
||||
std::uint64_t baseFee = baseFeeVote.getVotes ();
|
||||
std::uint32_t baseReserve = baseReserveVote.getVotes ();
|
||||
std::uint32_t incReserve = incReserveVote.getVotes ();
|
||||
std::uint64_t const baseFee = baseFeeVote.getVotes ();
|
||||
std::uint32_t const baseReserve = baseReserveVote.getVotes ();
|
||||
std::uint32_t const incReserve = incReserveVote.getVotes ();
|
||||
|
||||
// add transactions to our position
|
||||
if ((baseFee != lastClosedLedger->getBaseFee ()) ||
|
||||
(baseReserve != lastClosedLedger->getReserve (0)) ||
|
||||
(incReserve != lastClosedLedger->getReserveInc ()))
|
||||
{
|
||||
if (m_journal.warning) m_journal.warning <<
|
||||
if (journal_.warning) journal_.warning <<
|
||||
"We are voting for a fee change: " << baseFee <<
|
||||
"/" << baseReserve <<
|
||||
"/" << incReserve;
|
||||
@@ -197,37 +215,39 @@ public:
|
||||
|
||||
uint256 txID = trans.getTransactionID ();
|
||||
|
||||
if (m_journal.warning)
|
||||
m_journal.warning << "Vote: " << txID;
|
||||
if (journal_.warning)
|
||||
journal_.warning << "Vote: " << txID;
|
||||
|
||||
Serializer s;
|
||||
trans.add (s, true);
|
||||
|
||||
SHAMapItem::pointer tItem = std::make_shared<SHAMapItem> (txID, s.peekData ());
|
||||
SHAMapItem::pointer tItem = std::make_shared<SHAMapItem> (
|
||||
txID, s.peekData ());
|
||||
|
||||
if (!initialPosition->addGiveItem (tItem, true, false))
|
||||
{
|
||||
if (m_journal.warning) m_journal.warning <<
|
||||
if (journal_.warning) journal_.warning <<
|
||||
"Ledger already had fee change";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::uint64_t mTargetBaseFee;
|
||||
std::uint32_t mTargetReserveBase;
|
||||
std::uint32_t mTargetReserveIncrement;
|
||||
beast::Journal m_journal;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
std::unique_ptr<FeeVote>
|
||||
make_FeeVote (std::uint64_t targetBaseFee, std::uint32_t targetReserveBase,
|
||||
std::uint32_t targetReserveIncrement, beast::Journal journal)
|
||||
FeeVote::Setup
|
||||
setup_FeeVote (Section const& section)
|
||||
{
|
||||
return std::make_unique<FeeVoteImpl> (targetBaseFee, targetReserveBase,
|
||||
targetReserveIncrement, journal);
|
||||
FeeVote::Setup setup;
|
||||
set (setup.reference_fee, "reference_fee", section);
|
||||
set (setup.account_reserve, "account_reserve", section);
|
||||
set (setup.owner_reserve, "owner_reserve", section);
|
||||
return setup;
|
||||
}
|
||||
|
||||
std::unique_ptr<FeeVote>
|
||||
make_FeeVote (FeeVote::Setup const& setup, beast::Journal journal)
|
||||
{
|
||||
return std::make_unique<FeeVoteImpl> (setup, journal);
|
||||
}
|
||||
|
||||
} // ripple
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/book/Quality.h>
|
||||
#include <ripple/app/misc/FeeVote.h>
|
||||
#include <ripple/basics/Time.h>
|
||||
#include <ripple/basics/StringUtilities.h>
|
||||
#include <ripple/common/jsonrpc_fields.h>
|
||||
@@ -56,8 +57,8 @@ public:
|
||||
, m_clock (clock)
|
||||
, m_journal (journal)
|
||||
, m_localTX (LocalTxs::New ())
|
||||
, m_feeVote (make_FeeVote(10, 20 * SYSTEM_CURRENCY_PARTS,
|
||||
5 * SYSTEM_CURRENCY_PARTS, deprecatedLogs().journal("FeeVote")))
|
||||
, m_feeVote (make_FeeVote (setup_FeeVote (getConfig().section ("voting")),
|
||||
deprecatedLogs().journal("FeeVote")))
|
||||
, mMode (omDISCONNECTED)
|
||||
, mNeedNetworkLedger (false)
|
||||
, mProposing (false)
|
||||
|
||||
@@ -1,3 +1,64 @@
|
||||
# Fee Voting
|
||||
|
||||
The Ripple payment protocol enforces a fee schedule expressed in units of the
|
||||
native currency, XRP. Fees for transactions are paid directly from the account
|
||||
owner. There are also reserve requirements for each item that occupies storage
|
||||
in the ledger. The reserve fee schedule contains both a per-account reserve,
|
||||
and a per-owned-item reserve. The items an account may own include active
|
||||
offers, trust lines, and tickets.
|
||||
|
||||
Validators may vote to increase fees if they feel that the network is charging
|
||||
too little. They may also vote to decrease fees if the fees are too costly
|
||||
relative to the value the network provides. One common case where a validator
|
||||
may want to change fees is when the value of the native currency XRP fluctuates
|
||||
relative to other currencies.
|
||||
|
||||
The fee voting mechanism takes place every 256 ledgers ("voting ledgers"). In
|
||||
a voting ledger, each validator takes a position on what they think the fees
|
||||
should be. The consensus process converges on the majority position, and in
|
||||
subsequent ledgers a new fee schedule is enacted.
|
||||
|
||||
## Consensus
|
||||
|
||||
The Ripple consensus algorithm allows distributed participants to arrive at
|
||||
the same answer for yes/no questions. The canonical case for consensus is
|
||||
whether or not a particular transaction is included in the ledger. Fees
|
||||
present a more difficult challenge, since the decision on the new fee is not
|
||||
a yes or no question.
|
||||
|
||||
To convert validators' positions on fees into a yes or no question that can
|
||||
be converged in the consensus process, the following algorithm is used:
|
||||
|
||||
- In the ledger before a voting ledger, validators send proposals which also
|
||||
include the values they think the network should use for the new fee schedule.
|
||||
|
||||
- In the voting ledger, validators examine the proposals from other validators
|
||||
and choose a new fee schedule which moves the fees in a direction closer to
|
||||
the validator's ideal fee schedule and is also likely to be accepted. A fee
|
||||
amount is likely to be accepted if a majority of validators agree on the
|
||||
number.
|
||||
|
||||
- Each validator injects a "pseudo transaction" into their proposed ledger
|
||||
which sets the fees to the chosen schedule.
|
||||
|
||||
- The consensus process is applied to these fee-setting transactions as normal.
|
||||
Each transaction is either included in the ledger or not. In most cases, one
|
||||
fee setting transaction will make it in while the others are rejected. In
|
||||
some rare cases more than one fee setting transaction will make it in. The
|
||||
last one to be applied will take effect. This is harmless since a majority
|
||||
of validators still agreed on it.
|
||||
|
||||
- After the voting ledger has been validated, future pseudo transactions
|
||||
before the next voting ledger are rejected as fee setting transactions may
|
||||
only appear in voting ledgers.
|
||||
|
||||
## Configuration
|
||||
|
||||
A validating instance of rippled uses information in the configuration file
|
||||
to determine how it wants to vote on the fee schedule. It is the responsibility
|
||||
of the administrator to set these values.
|
||||
|
||||
---
|
||||
|
||||
# Amendment
|
||||
|
||||
|
||||
Reference in New Issue
Block a user