mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-08 19:26:45 +00:00
SmartEscrow fee voting changes
This commit is contained in:
@@ -1249,6 +1249,39 @@
|
||||
# Example:
|
||||
# owner_reserve = 2000000 # 2 XRP
|
||||
#
|
||||
# extension_compute_limit = <gas>
|
||||
#
|
||||
# The extension compute limit is the maximum amount of gas that can be
|
||||
# consumed by a single transaction. The gas limit is used to prevent
|
||||
# transactions from consuming too many resources.
|
||||
#
|
||||
# If this parameter is unspecified, rippled will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# extension_compute_limit = 1000000 # 1 million gas
|
||||
#
|
||||
# extension_size_limit = <bytes>
|
||||
#
|
||||
# The extension size limit is the maximum size of a WASM extension in
|
||||
# bytes. The size limit is used to prevent extensions from consuming
|
||||
# too many resources.
|
||||
#
|
||||
# If this parameter is unspecified, rippled will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# extension_size_limit = 100000 # 100 kb
|
||||
#
|
||||
# gas_price = <bytes>
|
||||
#
|
||||
# The gas price is the conversion between WASM gas and its price in drops.
|
||||
#
|
||||
# If this parameter is unspecified, rippled will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# gas_price = 1000000 # 1 drop per gas
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 9. Misc Settings
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
constexpr std::uint32_t MICRO_DROPS_PER_DROP{1'000'000};
|
||||
|
||||
/** Reflects the fee settings for a particular ledger.
|
||||
|
||||
The fees are always the same for any transactions applied
|
||||
@@ -34,6 +36,10 @@ struct Fees
|
||||
XRPAmount base{0}; // Reference tx cost (drops)
|
||||
XRPAmount reserve{0}; // Reserve base (drops)
|
||||
XRPAmount increment{0}; // Reserve increment (drops)
|
||||
std::uint32_t extensionComputeLimit{
|
||||
0}; // Extension compute limit (instructions)
|
||||
std::uint32_t extensionSizeLimit{0}; // Extension size limit (bytes)
|
||||
std::uint32_t gasPrice{0}; // price of WASM gas (micro-drops)
|
||||
|
||||
explicit Fees() = default;
|
||||
Fees(Fees const&) = default;
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
// If you add an amendment here, then do not forget to increment `numFeatures`
|
||||
// in include/xrpl/protocol/Feature.h.
|
||||
|
||||
XRPL_FEATURE(SmartEscrow, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (IncludeKeyletFields, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(DynamicMPT, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (TokenEscrowV1, Supported::yes, VoteBehavior::DefaultNo)
|
||||
|
||||
@@ -320,6 +320,11 @@ LEDGER_ENTRY(ltFEE_SETTINGS, 0x0073, FeeSettings, fee, ({
|
||||
{sfBaseFeeDrops, soeOPTIONAL},
|
||||
{sfReserveBaseDrops, soeOPTIONAL},
|
||||
{sfReserveIncrementDrops, soeOPTIONAL},
|
||||
// Smart Escrow fields
|
||||
{sfExtensionComputeLimit, soeOPTIONAL},
|
||||
{sfExtensionSizeLimit, soeOPTIONAL},
|
||||
{sfGasPrice, soeOPTIONAL},
|
||||
|
||||
{sfPreviousTxnID, soeOPTIONAL},
|
||||
{sfPreviousTxnLgrSeq, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
@@ -115,6 +115,9 @@ TYPED_SFIELD(sfFirstNFTokenSequence, UINT32, 50)
|
||||
TYPED_SFIELD(sfOracleDocumentID, UINT32, 51)
|
||||
TYPED_SFIELD(sfPermissionValue, UINT32, 52)
|
||||
TYPED_SFIELD(sfMutableFlags, UINT32, 53)
|
||||
TYPED_SFIELD(sfExtensionComputeLimit, UINT32, 54)
|
||||
TYPED_SFIELD(sfExtensionSizeLimit, UINT32, 55)
|
||||
TYPED_SFIELD(sfGasPrice, UINT32, 56)
|
||||
|
||||
// 64-bit integers (common)
|
||||
TYPED_SFIELD(sfIndexNext, UINT64, 1)
|
||||
|
||||
@@ -978,6 +978,10 @@ TRANSACTION(ttFEE, 101, SetFee,
|
||||
{sfBaseFeeDrops, soeOPTIONAL},
|
||||
{sfReserveBaseDrops, soeOPTIONAL},
|
||||
{sfReserveIncrementDrops, soeOPTIONAL},
|
||||
// Smart Escrow fields
|
||||
{sfExtensionComputeLimit, soeOPTIONAL},
|
||||
{sfExtensionSizeLimit, soeOPTIONAL},
|
||||
{sfGasPrice, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This system-generated transaction type is used to update the network's negative UNL
|
||||
|
||||
@@ -272,6 +272,9 @@ JSS(expected_date_UTC); // out: any (warnings)
|
||||
JSS(expected_ledger_size); // out: TxQ
|
||||
JSS(expiration); // out: AccountOffers, AccountChannels,
|
||||
// ValidatorList, amm_info
|
||||
JSS(extension_compute); // out: NetworkOps
|
||||
JSS(extension_size); // out: NetworkOps
|
||||
JSS(gas_price); // out: NetworkOps
|
||||
JSS(fail_hard); // in: Sign, Submit
|
||||
JSS(failed); // out: InboundLedger
|
||||
JSS(feature); // in: Feature
|
||||
@@ -722,11 +725,11 @@ JSS(write_load); // out: GetCounts
|
||||
#pragma push_macro("LEDGER_ENTRY_DUPLICATE")
|
||||
#undef LEDGER_ENTRY_DUPLICATE
|
||||
|
||||
#define LEDGER_ENTRY(tag, value, name, rpcName, ...) \
|
||||
JSS(name); \
|
||||
#define LEDGER_ENTRY(tag, value, name, rpcName, fields) \
|
||||
JSS(name); \
|
||||
JSS(rpcName);
|
||||
|
||||
#define LEDGER_ENTRY_DUPLICATE(tag, value, name, rpcName, ...) JSS(rpcName);
|
||||
#define LEDGER_ENTRY_DUPLICATE(tag, value, name, rpcName, fields) JSS(rpcName);
|
||||
|
||||
#include <xrpl/protocol/detail/ledger_entries.macro>
|
||||
|
||||
|
||||
@@ -78,6 +78,10 @@ STValidation::validationFormat()
|
||||
{sfBaseFeeDrops, soeOPTIONAL},
|
||||
{sfReserveBaseDrops, soeOPTIONAL},
|
||||
{sfReserveIncrementDrops, soeOPTIONAL},
|
||||
// featureSmartEscrow
|
||||
{sfExtensionComputeLimit, soeOPTIONAL},
|
||||
{sfExtensionSizeLimit, soeOPTIONAL},
|
||||
{sfGasPrice, soeOPTIONAL},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ class FeeVote_test : public beast::unit_test::suite
|
||||
void
|
||||
testSetup()
|
||||
{
|
||||
testcase("FeeVote setup");
|
||||
FeeSetup const defaultSetup;
|
||||
{
|
||||
// defaults
|
||||
@@ -37,36 +38,62 @@ class FeeVote_test : public beast::unit_test::suite
|
||||
BEAST_EXPECT(setup.reference_fee == defaultSetup.reference_fee);
|
||||
BEAST_EXPECT(setup.account_reserve == defaultSetup.account_reserve);
|
||||
BEAST_EXPECT(setup.owner_reserve == defaultSetup.owner_reserve);
|
||||
BEAST_EXPECT(
|
||||
setup.extension_compute_limit ==
|
||||
defaultSetup.extension_compute_limit);
|
||||
BEAST_EXPECT(
|
||||
setup.extension_size_limit ==
|
||||
defaultSetup.extension_size_limit);
|
||||
BEAST_EXPECT(setup.gas_price == defaultSetup.gas_price);
|
||||
}
|
||||
{
|
||||
Section config;
|
||||
config.append(
|
||||
{"reference_fee = 50",
|
||||
"account_reserve = 1234567",
|
||||
"owner_reserve = 1234"});
|
||||
"owner_reserve = 1234",
|
||||
"extension_compute_limit = 100",
|
||||
"extension_size_limit = 200",
|
||||
" gas_price = 300"});
|
||||
auto setup = setup_FeeVote(config);
|
||||
BEAST_EXPECT(setup.reference_fee == 50);
|
||||
BEAST_EXPECT(setup.account_reserve == 1234567);
|
||||
BEAST_EXPECT(setup.owner_reserve == 1234);
|
||||
BEAST_EXPECT(setup.extension_compute_limit == 100);
|
||||
BEAST_EXPECT(setup.extension_size_limit == 200);
|
||||
BEAST_EXPECT(setup.gas_price == 300);
|
||||
}
|
||||
{
|
||||
Section config;
|
||||
config.append(
|
||||
{"reference_fee = blah",
|
||||
"account_reserve = yada",
|
||||
"owner_reserve = foo"});
|
||||
"owner_reserve = foo",
|
||||
"extension_compute_limit = bar",
|
||||
"extension_size_limit = baz",
|
||||
"gas_price = qux"});
|
||||
// Illegal values are ignored, and the defaults left unchanged
|
||||
auto setup = setup_FeeVote(config);
|
||||
BEAST_EXPECT(setup.reference_fee == defaultSetup.reference_fee);
|
||||
BEAST_EXPECT(setup.account_reserve == defaultSetup.account_reserve);
|
||||
BEAST_EXPECT(setup.owner_reserve == defaultSetup.owner_reserve);
|
||||
BEAST_EXPECT(
|
||||
setup.extension_compute_limit ==
|
||||
defaultSetup.extension_compute_limit);
|
||||
BEAST_EXPECT(
|
||||
setup.extension_size_limit ==
|
||||
defaultSetup.extension_size_limit);
|
||||
BEAST_EXPECT(setup.gas_price == defaultSetup.gas_price);
|
||||
}
|
||||
{
|
||||
Section config;
|
||||
config.append(
|
||||
{"reference_fee = -50",
|
||||
"account_reserve = -1234567",
|
||||
"owner_reserve = -1234"});
|
||||
"owner_reserve = -1234",
|
||||
"extension_compute_limit = -100",
|
||||
"extension_size_limit = -200",
|
||||
"gas_price = -300"});
|
||||
// Illegal values are ignored, and the defaults left unchanged
|
||||
auto setup = setup_FeeVote(config);
|
||||
BEAST_EXPECT(setup.reference_fee == defaultSetup.reference_fee);
|
||||
@@ -74,6 +101,12 @@ class FeeVote_test : public beast::unit_test::suite
|
||||
setup.account_reserve == static_cast<std::uint32_t>(-1234567));
|
||||
BEAST_EXPECT(
|
||||
setup.owner_reserve == static_cast<std::uint32_t>(-1234));
|
||||
BEAST_EXPECT(
|
||||
setup.extension_compute_limit ==
|
||||
static_cast<std::uint32_t>(-100));
|
||||
BEAST_EXPECT(
|
||||
setup.extension_size_limit == static_cast<std::uint32_t>(-200));
|
||||
BEAST_EXPECT(setup.gas_price == static_cast<std::uint32_t>(-300));
|
||||
}
|
||||
{
|
||||
auto const big64 = std::to_string(
|
||||
@@ -84,12 +117,22 @@ class FeeVote_test : public beast::unit_test::suite
|
||||
config.append(
|
||||
{"reference_fee = " + big64,
|
||||
"account_reserve = " + big64,
|
||||
"owner_reserve = " + big64});
|
||||
"owner_reserve = " + big64,
|
||||
"extension_compute_limit = " + big64,
|
||||
"extension_size_limit = " + big64,
|
||||
"gas_price = " + big64});
|
||||
// Illegal values are ignored, and the defaults left unchanged
|
||||
auto setup = setup_FeeVote(config);
|
||||
BEAST_EXPECT(setup.reference_fee == defaultSetup.reference_fee);
|
||||
BEAST_EXPECT(setup.account_reserve == defaultSetup.account_reserve);
|
||||
BEAST_EXPECT(setup.owner_reserve == defaultSetup.owner_reserve);
|
||||
BEAST_EXPECT(
|
||||
setup.extension_compute_limit ==
|
||||
defaultSetup.extension_compute_limit);
|
||||
BEAST_EXPECT(
|
||||
setup.extension_size_limit ==
|
||||
defaultSetup.extension_size_limit);
|
||||
BEAST_EXPECT(setup.gas_price == defaultSetup.gas_price);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,12 @@ struct PseudoTx_test : public beast::unit_test::suite
|
||||
obj[sfReserveIncrement] = 0;
|
||||
obj[sfReferenceFeeUnits] = 0;
|
||||
}
|
||||
if (rules.enabled(featureSmartEscrow))
|
||||
{
|
||||
obj[sfExtensionComputeLimit] = 0;
|
||||
obj[sfExtensionSizeLimit] = 0;
|
||||
obj[sfGasPrice] = 0;
|
||||
}
|
||||
}));
|
||||
|
||||
res.emplace_back(STTx(ttAMENDMENT, [&](auto& obj) {
|
||||
@@ -118,7 +124,9 @@ struct PseudoTx_test : public beast::unit_test::suite
|
||||
FeatureBitset const all{testable_amendments()};
|
||||
FeatureBitset const xrpFees{featureXRPFees};
|
||||
|
||||
testPrevented(all - featureXRPFees - featureSmartEscrow);
|
||||
testPrevented(all - featureXRPFees);
|
||||
testPrevented(all - featureSmartEscrow);
|
||||
testPrevented(all);
|
||||
testAllowed();
|
||||
}
|
||||
|
||||
@@ -532,6 +532,22 @@ public:
|
||||
if (jv.isMember(jss::reserve_inc) != isFlagLedger)
|
||||
return false;
|
||||
|
||||
if (env.closed()->rules().enabled(featureSmartEscrow))
|
||||
{
|
||||
if (jv.isMember(jss::extension_compute) != isFlagLedger)
|
||||
return false;
|
||||
|
||||
if (jv.isMember(jss::extension_size) != isFlagLedger)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (jv.isMember(jss::extension_compute))
|
||||
return false;
|
||||
|
||||
if (jv.isMember(jss::extension_size))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -1596,7 +1612,8 @@ public:
|
||||
testTransactions_APIv1();
|
||||
testTransactions_APIv2();
|
||||
testManifests();
|
||||
testValidations(all - xrpFees);
|
||||
testValidations(all - featureXRPFees - featureSmartEscrow);
|
||||
testValidations(all - featureSmartEscrow);
|
||||
testValidations(all);
|
||||
testSubErrors(true);
|
||||
testSubErrors(false);
|
||||
|
||||
@@ -221,6 +221,15 @@ Ledger::Ledger(
|
||||
sle->at(sfReserveIncrement) = *f;
|
||||
sle->at(sfReferenceFeeUnits) = Config::FEE_UNITS_DEPRECATED;
|
||||
}
|
||||
if (std::find(
|
||||
amendments.begin(), amendments.end(), featureSmartEscrow) !=
|
||||
amendments.end())
|
||||
{
|
||||
sle->at(sfExtensionComputeLimit) =
|
||||
config.FEES.extension_compute_limit;
|
||||
sle->at(sfExtensionSizeLimit) = config.FEES.extension_size_limit;
|
||||
sle->at(sfGasPrice) = config.FEES.gas_price;
|
||||
}
|
||||
rawInsert(sle);
|
||||
}
|
||||
|
||||
@@ -612,6 +621,7 @@ Ledger::setup()
|
||||
{
|
||||
bool oldFees = false;
|
||||
bool newFees = false;
|
||||
bool extensionFees = false;
|
||||
{
|
||||
auto const baseFee = sle->at(~sfBaseFee);
|
||||
auto const reserveBase = sle->at(~sfReserveBase);
|
||||
@@ -629,6 +639,7 @@ Ledger::setup()
|
||||
auto const reserveBaseXRP = sle->at(~sfReserveBaseDrops);
|
||||
auto const reserveIncrementXRP =
|
||||
sle->at(~sfReserveIncrementDrops);
|
||||
|
||||
auto assign = [&ret](
|
||||
XRPAmount& dest,
|
||||
std::optional<STAmount> const& src) {
|
||||
@@ -645,12 +656,35 @@ Ledger::setup()
|
||||
assign(fees_.increment, reserveIncrementXRP);
|
||||
newFees = baseFeeXRP || reserveBaseXRP || reserveIncrementXRP;
|
||||
}
|
||||
{
|
||||
auto const extensionComputeLimit =
|
||||
sle->at(~sfExtensionComputeLimit);
|
||||
auto const extensionSizeLimit = sle->at(~sfExtensionSizeLimit);
|
||||
auto const gasPrice = sle->at(~sfGasPrice);
|
||||
|
||||
auto assign = [](std::uint32_t& dest,
|
||||
std::optional<std::uint32_t> const& src) {
|
||||
if (src)
|
||||
{
|
||||
dest = src.value();
|
||||
}
|
||||
};
|
||||
assign(fees_.extensionComputeLimit, extensionComputeLimit);
|
||||
assign(fees_.extensionSizeLimit, extensionSizeLimit);
|
||||
assign(fees_.gasPrice, gasPrice);
|
||||
extensionFees =
|
||||
extensionComputeLimit || extensionSizeLimit || gasPrice;
|
||||
}
|
||||
if (oldFees && newFees)
|
||||
// Should be all of one or the other, but not both
|
||||
ret = false;
|
||||
if (!rules_.enabled(featureXRPFees) && newFees)
|
||||
// Can't populate the new fees before the amendment is enabled
|
||||
ret = false;
|
||||
if (!rules_.enabled(featureSmartEscrow) && extensionFees)
|
||||
// Can't populate the extension fees before the amendment is
|
||||
// enabled
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
catch (SHAMapMissingNode const&)
|
||||
@@ -669,15 +703,20 @@ Ledger::setup()
|
||||
void
|
||||
Ledger::defaultFees(Config const& config)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
fees_.base == 0 && fees_.reserve == 0 && fees_.increment == 0,
|
||||
"ripple::Ledger::defaultFees : zero fees");
|
||||
assert(
|
||||
fees_.base == 0 && fees_.reserve == 0 && fees_.increment == 0 &&
|
||||
fees_.extensionComputeLimit == 0 && fees_.extensionSizeLimit == 0 &&
|
||||
fees_.gasPrice == 0);
|
||||
if (fees_.base == 0)
|
||||
fees_.base = config.FEES.reference_fee;
|
||||
if (fees_.reserve == 0)
|
||||
fees_.reserve = config.FEES.account_reserve;
|
||||
if (fees_.increment == 0)
|
||||
fees_.increment = config.FEES.owner_reserve;
|
||||
if (fees_.extensionComputeLimit == 0)
|
||||
fees_.extensionComputeLimit = config.FEES.extension_compute_limit;
|
||||
if (fees_.extensionSizeLimit == 0)
|
||||
fees_.extensionSizeLimit = config.FEES.extension_size_limit;
|
||||
if (fees_.gasPrice == 0)
|
||||
fees_.gasPrice = config.FEES.gas_price;
|
||||
}
|
||||
|
||||
std::shared_ptr<SLE>
|
||||
|
||||
@@ -28,10 +28,10 @@ namespace ripple {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename value_type>
|
||||
class VotableValue
|
||||
{
|
||||
private:
|
||||
using value_type = XRPAmount;
|
||||
value_type const current_; // The current setting
|
||||
value_type const target_; // The setting we want
|
||||
std::map<value_type, int> voteMap_;
|
||||
@@ -66,8 +66,9 @@ public:
|
||||
getVotes() const;
|
||||
};
|
||||
|
||||
auto
|
||||
VotableValue::getVotes() const -> std::pair<value_type, bool>
|
||||
template <typename value_type>
|
||||
std::pair<value_type, bool>
|
||||
VotableValue<value_type>::getVotes() const
|
||||
{
|
||||
value_type ourVote = current_;
|
||||
int weight = 0;
|
||||
@@ -190,6 +191,33 @@ FeeVoteImpl::doValidation(
|
||||
"reserve increment",
|
||||
sfReserveIncrement);
|
||||
}
|
||||
if (rules.enabled(featureSmartEscrow))
|
||||
{
|
||||
auto vote = [&v, this](
|
||||
auto const current,
|
||||
std::uint32_t target,
|
||||
char const* name,
|
||||
auto const& sfield) {
|
||||
if (current != target)
|
||||
{
|
||||
JLOG(journal_.info())
|
||||
<< "Voting for " << name << " of " << target;
|
||||
|
||||
v[sfield] = target;
|
||||
}
|
||||
};
|
||||
vote(
|
||||
lastFees.extensionComputeLimit,
|
||||
target_.extension_compute_limit,
|
||||
"extension compute limit",
|
||||
sfExtensionComputeLimit);
|
||||
vote(
|
||||
lastFees.extensionSizeLimit,
|
||||
target_.extension_size_limit,
|
||||
"extension size limit",
|
||||
sfExtensionSizeLimit);
|
||||
vote(lastFees.gasPrice, target_.gas_price, "gas price", sfGasPrice);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -212,11 +240,22 @@ FeeVoteImpl::doVoting(
|
||||
detail::VotableValue incReserveVote(
|
||||
lastClosedLedger->fees().increment, target_.owner_reserve);
|
||||
|
||||
detail::VotableValue extensionComputeVote(
|
||||
lastClosedLedger->fees().extensionComputeLimit,
|
||||
target_.extension_compute_limit);
|
||||
|
||||
detail::VotableValue extensionSizeVote(
|
||||
lastClosedLedger->fees().extensionSizeLimit,
|
||||
target_.extension_size_limit);
|
||||
|
||||
detail::VotableValue gasPriceVote(
|
||||
lastClosedLedger->fees().gasPrice, target_.gas_price);
|
||||
|
||||
auto const& rules = lastClosedLedger->rules();
|
||||
if (rules.enabled(featureXRPFees))
|
||||
{
|
||||
auto doVote = [](std::shared_ptr<STValidation> const& val,
|
||||
detail::VotableValue& value,
|
||||
detail::VotableValue<XRPAmount>& value,
|
||||
SF_AMOUNT const& xrpField) {
|
||||
if (auto const field = ~val->at(~xrpField);
|
||||
field && field->native())
|
||||
@@ -245,7 +284,7 @@ FeeVoteImpl::doVoting(
|
||||
else
|
||||
{
|
||||
auto doVote = [](std::shared_ptr<STValidation> const& val,
|
||||
detail::VotableValue& value,
|
||||
detail::VotableValue<XRPAmount>& value,
|
||||
auto const& valueField) {
|
||||
if (auto const field = val->at(~valueField))
|
||||
{
|
||||
@@ -276,6 +315,30 @@ FeeVoteImpl::doVoting(
|
||||
doVote(val, incReserveVote, sfReserveIncrement);
|
||||
}
|
||||
}
|
||||
if (rules.enabled(featureSmartEscrow))
|
||||
{
|
||||
auto doVote = [](std::shared_ptr<STValidation> const& val,
|
||||
detail::VotableValue<std::uint32_t>& value,
|
||||
SF_UINT32 const& extensionField) {
|
||||
if (auto const field = ~val->at(~extensionField); field)
|
||||
{
|
||||
value.addVote(field.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
value.noVote();
|
||||
}
|
||||
};
|
||||
|
||||
for (auto const& val : set)
|
||||
{
|
||||
if (!val->isTrusted())
|
||||
continue;
|
||||
doVote(val, extensionComputeVote, sfExtensionComputeLimit);
|
||||
doVote(val, extensionSizeVote, sfExtensionSizeLimit);
|
||||
doVote(val, gasPriceVote, sfGasPrice);
|
||||
}
|
||||
}
|
||||
|
||||
// choose our positions
|
||||
// TODO: Use structured binding once LLVM 16 is the minimum supported
|
||||
@@ -284,11 +347,15 @@ FeeVoteImpl::doVoting(
|
||||
auto const baseFee = baseFeeVote.getVotes();
|
||||
auto const baseReserve = baseReserveVote.getVotes();
|
||||
auto const incReserve = incReserveVote.getVotes();
|
||||
auto const extensionCompute = extensionComputeVote.getVotes();
|
||||
auto const extensionSize = extensionSizeVote.getVotes();
|
||||
auto const gasPrice = gasPriceVote.getVotes();
|
||||
|
||||
auto const seq = lastClosedLedger->info().seq + 1;
|
||||
|
||||
// add transactions to our position
|
||||
if (baseFee.second || baseReserve.second || incReserve.second)
|
||||
if (baseFee.second || baseReserve.second || incReserve.second ||
|
||||
extensionCompute.second || extensionSize.second || gasPrice.second)
|
||||
{
|
||||
JLOG(journal_.warn())
|
||||
<< "We are voting for a fee change: " << baseFee.first << "/"
|
||||
@@ -316,6 +383,12 @@ FeeVoteImpl::doVoting(
|
||||
incReserveVote.current());
|
||||
obj[sfReferenceFeeUnits] = Config::FEE_UNITS_DEPRECATED;
|
||||
}
|
||||
if (rules.enabled(featureSmartEscrow))
|
||||
{
|
||||
obj[sfExtensionComputeLimit] = extensionCompute.first;
|
||||
obj[sfExtensionSizeLimit] = extensionSize.first;
|
||||
obj[sfGasPrice] = gasPrice.first;
|
||||
}
|
||||
});
|
||||
|
||||
uint256 txID = feeTx.getTransactionID();
|
||||
|
||||
@@ -1452,11 +1452,6 @@ NetworkOPsImp::processTransactionSet(CanonicalTXSet const& set)
|
||||
for (auto& t : transactions)
|
||||
mTransactions.push_back(std::move(t));
|
||||
}
|
||||
if (mTransactions.empty())
|
||||
{
|
||||
JLOG(m_journal.debug()) << "No transaction to process!";
|
||||
return;
|
||||
}
|
||||
|
||||
doTransactionSyncBatch(lock, [&](std::unique_lock<std::mutex> const&) {
|
||||
XRPL_ASSERT(
|
||||
@@ -2482,6 +2477,18 @@ NetworkOPsImp::pubValidation(std::shared_ptr<STValidation> const& val)
|
||||
reserveIncXRP && reserveIncXRP->native())
|
||||
jvObj[jss::reserve_inc] = reserveIncXRP->xrp().jsonClipped();
|
||||
|
||||
if (auto const extensionComputeLimit =
|
||||
~val->at(~sfExtensionComputeLimit);
|
||||
extensionComputeLimit)
|
||||
jvObj[jss::extension_compute] = *extensionComputeLimit;
|
||||
|
||||
if (auto const extensionSizeLimit = ~val->at(~sfExtensionSizeLimit);
|
||||
extensionSizeLimit)
|
||||
jvObj[jss::extension_size] = *extensionSizeLimit;
|
||||
|
||||
if (auto const gasPrice = ~val->at(~sfGasPrice); gasPrice)
|
||||
jvObj[jss::gas_price] = *gasPrice;
|
||||
|
||||
// NOTE Use MultiApiJson to publish two slightly different JSON objects
|
||||
// for consumers supporting different API versions
|
||||
MultiApiJson multiObj{jvObj};
|
||||
@@ -2931,12 +2938,22 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters)
|
||||
l[jss::seq] = Json::UInt(lpClosed->info().seq);
|
||||
l[jss::hash] = to_string(lpClosed->info().hash);
|
||||
|
||||
bool const smartEscrowEnabled =
|
||||
m_ledgerMaster.getValidatedLedger()->rules().enabled(
|
||||
featureSmartEscrow);
|
||||
if (!human)
|
||||
{
|
||||
l[jss::base_fee] = baseFee.jsonClipped();
|
||||
l[jss::reserve_base] =
|
||||
lpClosed->fees().accountReserve(0).jsonClipped();
|
||||
l[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
|
||||
if (smartEscrowEnabled)
|
||||
{
|
||||
l[jss::extension_compute] =
|
||||
lpClosed->fees().extensionComputeLimit;
|
||||
l[jss::extension_size] = lpClosed->fees().extensionSizeLimit;
|
||||
l[jss::gas_price] = lpClosed->fees().gasPrice;
|
||||
}
|
||||
l[jss::close_time] = Json::Value::UInt(
|
||||
lpClosed->info().closeTime.time_since_epoch().count());
|
||||
}
|
||||
@@ -2946,6 +2963,13 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters)
|
||||
l[jss::reserve_base_xrp] =
|
||||
lpClosed->fees().accountReserve(0).decimalXRP();
|
||||
l[jss::reserve_inc_xrp] = lpClosed->fees().increment.decimalXRP();
|
||||
if (smartEscrowEnabled)
|
||||
{
|
||||
l[jss::extension_compute] =
|
||||
lpClosed->fees().extensionComputeLimit;
|
||||
l[jss::extension_size] = lpClosed->fees().extensionSizeLimit;
|
||||
l[jss::gas_price] = lpClosed->fees().gasPrice;
|
||||
}
|
||||
|
||||
if (auto const closeOffset = app_.timeKeeper().closeOffset();
|
||||
std::abs(closeOffset.count()) >= 60)
|
||||
@@ -3138,6 +3162,14 @@ NetworkOPsImp::pubLedger(std::shared_ptr<ReadView const> const& lpAccepted)
|
||||
lpAccepted->fees().accountReserve(0).jsonClipped();
|
||||
jvObj[jss::reserve_inc] =
|
||||
lpAccepted->fees().increment.jsonClipped();
|
||||
if (lpAccepted->rules().enabled(featureSmartEscrow))
|
||||
{
|
||||
jvObj[jss::extension_compute] =
|
||||
lpAccepted->fees().extensionComputeLimit;
|
||||
jvObj[jss::extension_size] =
|
||||
lpAccepted->fees().extensionSizeLimit;
|
||||
jvObj[jss::gas_price] = lpAccepted->fees().gasPrice;
|
||||
}
|
||||
|
||||
jvObj[jss::txn_count] = Json::UInt(alpAccepted->size());
|
||||
|
||||
@@ -3508,8 +3540,8 @@ NetworkOPsImp::pubAccountTransaction(
|
||||
}
|
||||
|
||||
JLOG(m_journal.trace())
|
||||
<< "pubAccountTransaction: "
|
||||
<< "proposed=" << iProposed << ", accepted=" << iAccepted;
|
||||
<< "pubAccountTransaction: " << "proposed=" << iProposed
|
||||
<< ", accepted=" << iAccepted;
|
||||
|
||||
if (!notify.empty() || !accountHistoryNotify.empty())
|
||||
{
|
||||
@@ -4183,13 +4215,20 @@ NetworkOPsImp::subLedger(InfoSub::ref isrListener, Json::Value& jvResult)
|
||||
jvResult[jss::ledger_hash] = to_string(lpClosed->info().hash);
|
||||
jvResult[jss::ledger_time] = Json::Value::UInt(
|
||||
lpClosed->info().closeTime.time_since_epoch().count());
|
||||
jvResult[jss::network_id] = app_.config().NETWORK_ID;
|
||||
if (!lpClosed->rules().enabled(featureXRPFees))
|
||||
jvResult[jss::fee_ref] = Config::FEE_UNITS_DEPRECATED;
|
||||
jvResult[jss::fee_base] = lpClosed->fees().base.jsonClipped();
|
||||
jvResult[jss::reserve_base] =
|
||||
lpClosed->fees().accountReserve(0).jsonClipped();
|
||||
jvResult[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
|
||||
jvResult[jss::network_id] = app_.config().NETWORK_ID;
|
||||
if (lpClosed->rules().enabled(featureSmartEscrow))
|
||||
{
|
||||
jvResult[jss::extension_compute] =
|
||||
lpClosed->fees().extensionComputeLimit;
|
||||
jvResult[jss::extension_size] = lpClosed->fees().extensionSizeLimit;
|
||||
jvResult[jss::gas_price] = lpClosed->fees().gasPrice;
|
||||
}
|
||||
}
|
||||
|
||||
if ((mMode >= OperatingMode::SYNCING) && !isNeedNetworkLedger())
|
||||
|
||||
@@ -130,6 +130,20 @@ Change::preclaim(PreclaimContext const& ctx)
|
||||
ctx.tx.isFieldPresent(sfReserveIncrementDrops))
|
||||
return temDISABLED;
|
||||
}
|
||||
if (ctx.view.rules().enabled(featureSmartEscrow))
|
||||
{
|
||||
if (!ctx.tx.isFieldPresent(sfExtensionComputeLimit) ||
|
||||
!ctx.tx.isFieldPresent(sfExtensionSizeLimit) ||
|
||||
!ctx.tx.isFieldPresent(sfGasPrice))
|
||||
return temMALFORMED;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ctx.tx.isFieldPresent(sfExtensionComputeLimit) ||
|
||||
ctx.tx.isFieldPresent(sfExtensionSizeLimit) ||
|
||||
ctx.tx.isFieldPresent(sfGasPrice))
|
||||
return temDISABLED;
|
||||
}
|
||||
return tesSUCCESS;
|
||||
case ttAMENDMENT:
|
||||
case ttUNL_MODIFY:
|
||||
@@ -377,6 +391,12 @@ Change::applyFee()
|
||||
set(feeObject, ctx_.tx, sfReserveBase);
|
||||
set(feeObject, ctx_.tx, sfReserveIncrement);
|
||||
}
|
||||
if (view().rules().enabled(featureSmartEscrow))
|
||||
{
|
||||
set(feeObject, ctx_.tx, sfExtensionComputeLimit);
|
||||
set(feeObject, ctx_.tx, sfExtensionSizeLimit);
|
||||
set(feeObject, ctx_.tx, sfGasPrice);
|
||||
}
|
||||
|
||||
view().update(feeObject);
|
||||
|
||||
|
||||
@@ -73,6 +73,15 @@ struct FeeSetup
|
||||
/** The per-owned item reserve requirement in drops. */
|
||||
XRPAmount owner_reserve{2 * DROPS_PER_XRP};
|
||||
|
||||
/** The compute limit for Feature Extensions. */
|
||||
std::uint32_t extension_compute_limit{1'000'000};
|
||||
|
||||
/** The WASM size limit for Feature Extensions. */
|
||||
std::uint32_t extension_size_limit{100'000};
|
||||
|
||||
/** The price of 1 WASM gas, in micro-drops. */
|
||||
std::uint32_t gas_price{1'000'000};
|
||||
|
||||
/* (Remember to update the example cfg files when changing any of these
|
||||
* values.) */
|
||||
};
|
||||
|
||||
@@ -1141,6 +1141,12 @@ setup_FeeVote(Section const& section)
|
||||
setup.account_reserve = temp;
|
||||
if (set(temp, "owner_reserve", section))
|
||||
setup.owner_reserve = temp;
|
||||
if (set(temp, "extension_compute_limit", section))
|
||||
setup.extension_compute_limit = temp;
|
||||
if (set(temp, "extension_size_limit", section))
|
||||
setup.extension_size_limit = temp;
|
||||
if (set(temp, "gas_price", section))
|
||||
setup.gas_price = temp;
|
||||
}
|
||||
return setup;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user