Compare commits

..

1 Commits

Author SHA1 Message Date
Peng Wang
52baedc571 a batch of memory, table, and trap tests 2025-12-02 17:31:31 -05:00
34 changed files with 574 additions and 648 deletions

View File

@@ -1290,39 +1290,6 @@
# 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

View File

@@ -5,8 +5,6 @@
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
@@ -17,10 +15,6 @@ 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;

View File

@@ -14,7 +14,6 @@
// Add new amendments to the top of this list.
// Keep it sorted in reverse chronological order.
XRPL_FEATURE(SmartEscrow, Supported::no, VoteBehavior::DefaultNo)
XRPL_FEATURE(PermissionDelegationV1_1, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (DirectoryLimit, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (IncludeKeyletFields, Supported::yes, VoteBehavior::DefaultNo)
@@ -30,6 +29,7 @@ XRPL_FEATURE(PermissionedDEX, Supported::yes, VoteBehavior::DefaultNo
XRPL_FEATURE(Batch, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(SingleAssetVault, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (PayChanCancelAfter, Supported::yes, VoteBehavior::DefaultNo)
// Check flags in Credential transactions
XRPL_FIX (InvalidTxFlags, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (FrozenLPTokenTransfer, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(DeepFreeze, Supported::yes, VoteBehavior::DefaultNo)

View File

@@ -301,11 +301,6 @@ 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},
}))

View File

@@ -96,9 +96,6 @@ 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)

View File

@@ -959,10 +959,6 @@ 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

View File

@@ -253,9 +253,6 @@ 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
@@ -707,11 +704,11 @@ JSS(write_load); // out: GetCounts
#pragma push_macro("LEDGER_ENTRY_DUPLICATE")
#undef LEDGER_ENTRY_DUPLICATE
#define LEDGER_ENTRY(tag, value, name, rpcName, fields) \
JSS(name); \
#define LEDGER_ENTRY(tag, value, name, rpcName, ...) \
JSS(name); \
JSS(rpcName);
#define LEDGER_ENTRY_DUPLICATE(tag, value, name, rpcName, fields) JSS(rpcName);
#define LEDGER_ENTRY_DUPLICATE(tag, value, name, rpcName, ...) JSS(rpcName);
#include <xrpl/protocol/detail/ledger_entries.macro>

View File

@@ -58,10 +58,6 @@ STValidation::validationFormat()
{sfBaseFeeDrops, soeOPTIONAL},
{sfReserveBaseDrops, soeOPTIONAL},
{sfReserveIncrementDrops, soeOPTIONAL},
// featureSmartEscrow
{sfExtensionComputeLimit, soeOPTIONAL},
{sfExtensionSizeLimit, soeOPTIONAL},
{sfGasPrice, soeOPTIONAL},
};
// clang-format on

View File

@@ -24,17 +24,13 @@ struct FeeSettingsFields
std::optional<XRPAmount> baseFeeDrops = std::nullopt;
std::optional<XRPAmount> reserveBaseDrops = std::nullopt;
std::optional<XRPAmount> reserveIncrementDrops = std::nullopt;
std::optional<std::uint32_t> extensionComputeLimit = std::nullopt;
std::optional<std::uint32_t> extensionSizeLimit = std::nullopt;
std::optional<std::uint32_t> gasPrice = std::nullopt;
};
STTx
createFeeTx(
Rules const& rules,
std::uint32_t seq,
FeeSettingsFields const& fields,
bool forceAllFields = false)
FeeSettingsFields const& fields)
{
auto fill = [&](auto& obj) {
obj.setAccountID(sfAccount, AccountID());
@@ -68,17 +64,6 @@ createFeeTx(
sfReferenceFeeUnits,
fields.referenceFeeUnits ? *fields.referenceFeeUnits : 0);
}
if (rules.enabled(featureSmartEscrow) || forceAllFields)
{
obj.setFieldU32(
sfExtensionComputeLimit,
fields.extensionComputeLimit ? *fields.extensionComputeLimit
: 0);
obj.setFieldU32(
sfExtensionSizeLimit,
fields.extensionSizeLimit ? *fields.extensionSizeLimit : 0);
obj.setFieldU32(sfGasPrice, fields.gasPrice ? *fields.gasPrice : 0);
}
};
return STTx(ttFEE, fill);
}
@@ -127,12 +112,6 @@ createInvalidFeeTx(
obj.setFieldU32(sfReserveIncrement, 50000);
obj.setFieldU32(sfReferenceFeeUnits, 10);
}
if (rules.enabled(featureSmartEscrow))
{
obj.setFieldU32(sfExtensionComputeLimit, 100 + uniqueValue);
obj.setFieldU32(sfExtensionSizeLimit, 200 + uniqueValue);
obj.setFieldU32(sfGasPrice, 300 + uniqueValue);
}
}
// If missingRequiredFields is true, we don't add the required fields
// (default behavior)
@@ -140,12 +119,12 @@ createInvalidFeeTx(
return STTx(ttFEE, fill);
}
TER
bool
applyFeeAndTestResult(jtx::Env& env, OpenView& view, STTx const& tx)
{
auto const res =
apply(env.app(), view, tx, ApplyFlags::tapNONE, env.journal);
return res.ter;
return res.ter == tesSUCCESS;
}
bool
@@ -201,25 +180,6 @@ verifyFeeObject(
if (!checkEquality(sfReferenceFeeUnits, expected.referenceFeeUnits))
return false;
}
if (rules.enabled(featureSmartEscrow))
{
if (!checkEquality(
sfExtensionComputeLimit,
expected.extensionComputeLimit.value_or(0)))
return false;
if (!checkEquality(
sfExtensionSizeLimit, expected.extensionSizeLimit.value_or(0)))
return false;
if (!checkEquality(sfGasPrice, expected.gasPrice.value_or(0)))
return false;
}
else
{
if (feeObject->isFieldPresent(sfExtensionComputeLimit) ||
feeObject->isFieldPresent(sfExtensionSizeLimit) ||
feeObject->isFieldPresent(sfGasPrice))
return false;
}
return true;
}
@@ -242,7 +202,6 @@ class FeeVote_test : public beast::unit_test::suite
void
testSetup()
{
testcase("FeeVote setup");
FeeSetup const defaultSetup;
{
// defaults
@@ -251,62 +210,36 @@ 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",
"extension_compute_limit = 100",
"extension_size_limit = 200",
" gas_price = 300"});
"owner_reserve = 1234"});
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",
"extension_compute_limit = bar",
"extension_size_limit = baz",
"gas_price = qux"});
"owner_reserve = foo"});
// 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",
"extension_compute_limit = -100",
"extension_size_limit = -200",
"gas_price = -300"});
"owner_reserve = -1234"});
// Illegal values are ignored, and the defaults left unchanged
auto setup = setup_FeeVote(config);
BEAST_EXPECT(setup.reference_fee == defaultSetup.reference_fee);
@@ -314,12 +247,6 @@ 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(
@@ -330,22 +257,12 @@ class FeeVote_test : public beast::unit_test::suite
config.append(
{"reference_fee = " + big64,
"account_reserve = " + big64,
"owner_reserve = " + big64,
"extension_compute_limit = " + big64,
"extension_size_limit = " + big64,
"gas_price = " + big64});
"owner_reserve = " + 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);
}
}
@@ -356,10 +273,7 @@ class FeeVote_test : public beast::unit_test::suite
// Test with XRPFees disabled (legacy format)
{
jtx::Env env(
*this,
jtx::testable_amendments() - featureXRPFees -
featureSmartEscrow);
jtx::Env env(*this, jtx::testable_amendments() - featureXRPFees);
auto ledger = std::make_shared<Ledger>(
create_genesis,
env.app().config(),
@@ -380,8 +294,7 @@ class FeeVote_test : public beast::unit_test::suite
auto feeTx = createFeeTx(ledger->rules(), ledger->seq(), fields);
OpenView accum(ledger.get());
BEAST_EXPECT(
isTesSuccess(applyFeeAndTestResult(env, accum, feeTx)));
BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx));
accum.apply(*ledger);
// Verify fee object was created/updated correctly
@@ -390,8 +303,7 @@ class FeeVote_test : public beast::unit_test::suite
// Test with XRPFees enabled (new format)
{
jtx::Env env(
*this, jtx::testable_amendments() - featureSmartEscrow);
jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees);
auto ledger = std::make_shared<Ledger>(
create_genesis,
env.app().config(),
@@ -410,76 +322,12 @@ class FeeVote_test : public beast::unit_test::suite
auto feeTx = createFeeTx(ledger->rules(), ledger->seq(), fields);
OpenView accum(ledger.get());
BEAST_EXPECT(
isTesSuccess(applyFeeAndTestResult(env, accum, feeTx)));
BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx));
accum.apply(*ledger);
// Verify fee object was created/updated correctly
BEAST_EXPECT(verifyFeeObject(ledger, ledger->rules(), fields));
}
// Test with both XRPFees and SmartEscrow enabled
{
jtx::Env env(*this, jtx::testable_amendments());
auto ledger = std::make_shared<Ledger>(
create_genesis,
env.app().config(),
std::vector<uint256>{},
env.app().getNodeFamily());
// Create the next ledger to apply transaction to
ledger = std::make_shared<Ledger>(
*ledger, env.app().timeKeeper().closeTime());
FeeSettingsFields fields{
.baseFeeDrops = XRPAmount{10},
.reserveBaseDrops = XRPAmount{200000},
.reserveIncrementDrops = XRPAmount{50000},
.extensionComputeLimit = 100,
.extensionSizeLimit = 200,
.gasPrice = 300};
// Test successful fee transaction with new fields
auto feeTx = createFeeTx(ledger->rules(), ledger->seq(), fields);
OpenView accum(ledger.get());
BEAST_EXPECT(
isTesSuccess(applyFeeAndTestResult(env, accum, feeTx)));
accum.apply(*ledger);
// Verify fee object was created/updated correctly
BEAST_EXPECT(verifyFeeObject(ledger, ledger->rules(), fields));
}
// Test that the Smart Escrow fields are rejected if the
// feature is disabled
{
jtx::Env env(
*this, jtx::testable_amendments() - featureSmartEscrow);
auto ledger = std::make_shared<Ledger>(
create_genesis,
env.app().config(),
std::vector<uint256>{},
env.app().getNodeFamily());
// Create the next ledger to apply transaction to
ledger = std::make_shared<Ledger>(
*ledger, env.app().timeKeeper().closeTime());
FeeSettingsFields fields{
.baseFeeDrops = XRPAmount{10},
.reserveBaseDrops = XRPAmount{200000},
.reserveIncrementDrops = XRPAmount{50000},
.extensionComputeLimit = 100,
.extensionSizeLimit = 200,
.gasPrice = 300};
// Test successful fee transaction with new fields
auto feeTx =
createFeeTx(ledger->rules(), ledger->seq(), fields, true);
OpenView accum(ledger.get());
BEAST_EXPECT(
!isTesSuccess(applyFeeAndTestResult(env, accum, feeTx)));
}
}
void
@@ -488,10 +336,7 @@ class FeeVote_test : public beast::unit_test::suite
testcase("Fee Transaction Validation");
{
jtx::Env env(
*this,
jtx::testable_amendments() - featureXRPFees -
featureSmartEscrow);
jtx::Env env(*this, jtx::testable_amendments() - featureXRPFees);
auto ledger = std::make_shared<Ledger>(
create_genesis,
env.app().config(),
@@ -506,19 +351,16 @@ class FeeVote_test : public beast::unit_test::suite
auto invalidTx = createInvalidFeeTx(
ledger->rules(), ledger->seq(), true, false, 1);
OpenView accum(ledger.get());
BEAST_EXPECT(
!isTesSuccess(applyFeeAndTestResult(env, accum, invalidTx)));
BEAST_EXPECT(!applyFeeAndTestResult(env, accum, invalidTx));
// Test transaction with new format fields when XRPFees is disabled
auto disallowedTx = createInvalidFeeTx(
ledger->rules(), ledger->seq(), false, true, 2);
BEAST_EXPECT(
!isTesSuccess(applyFeeAndTestResult(env, accum, disallowedTx)));
BEAST_EXPECT(!applyFeeAndTestResult(env, accum, disallowedTx));
}
{
jtx::Env env(
*this, jtx::testable_amendments() - featureSmartEscrow);
jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees);
auto ledger = std::make_shared<Ledger>(
create_genesis,
env.app().config(),
@@ -533,43 +375,12 @@ class FeeVote_test : public beast::unit_test::suite
auto invalidTx = createInvalidFeeTx(
ledger->rules(), ledger->seq(), true, false, 3);
OpenView accum(ledger.get());
BEAST_EXPECT(
!isTesSuccess(applyFeeAndTestResult(env, accum, invalidTx)));
BEAST_EXPECT(!applyFeeAndTestResult(env, accum, invalidTx));
// Test transaction with legacy fields when XRPFees is enabled
auto disallowedTx = createInvalidFeeTx(
ledger->rules(), ledger->seq(), false, true, 4);
BEAST_EXPECT(
!isTesSuccess(applyFeeAndTestResult(env, accum, disallowedTx)));
}
{
jtx::Env env(
*this,
jtx::testable_amendments() | featureXRPFees |
featureSmartEscrow);
auto ledger = std::make_shared<Ledger>(
create_genesis,
env.app().config(),
std::vector<uint256>{},
env.app().getNodeFamily());
// Create the next ledger to apply transaction to
ledger = std::make_shared<Ledger>(
*ledger, env.app().timeKeeper().closeTime());
// Test transaction with missing required new fields
auto invalidTx = createInvalidFeeTx(
ledger->rules(), ledger->seq(), true, false, 5);
OpenView accum(ledger.get());
BEAST_EXPECT(
!isTesSuccess(applyFeeAndTestResult(env, accum, invalidTx)));
// Test transaction with legacy fields when XRPFees is enabled
auto disallowedTx = createInvalidFeeTx(
ledger->rules(), ledger->seq(), false, true, 6);
BEAST_EXPECT(
!isTesSuccess(applyFeeAndTestResult(env, accum, disallowedTx)));
BEAST_EXPECT(!applyFeeAndTestResult(env, accum, disallowedTx));
}
}
@@ -578,7 +389,7 @@ class FeeVote_test : public beast::unit_test::suite
{
testcase("Pseudo Transaction Properties");
jtx::Env env(*this, jtx::testable_amendments() - featureSmartEscrow);
jtx::Env env(*this, jtx::testable_amendments());
auto ledger = std::make_shared<Ledger>(
create_genesis,
env.app().config(),
@@ -608,8 +419,7 @@ class FeeVote_test : public beast::unit_test::suite
// But can be applied to a closed ledger
{
OpenView closedAccum(ledger.get());
BEAST_EXPECT(
isTesSuccess(applyFeeAndTestResult(env, closedAccum, feeTx)));
BEAST_EXPECT(applyFeeAndTestResult(env, closedAccum, feeTx));
}
}
@@ -618,7 +428,7 @@ class FeeVote_test : public beast::unit_test::suite
{
testcase("Multiple Fee Updates");
jtx::Env env(*this, jtx::testable_amendments() - featureSmartEscrow);
jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees);
auto ledger = std::make_shared<Ledger>(
create_genesis,
env.app().config(),
@@ -636,8 +446,7 @@ class FeeVote_test : public beast::unit_test::suite
{
OpenView accum(ledger.get());
BEAST_EXPECT(
isTesSuccess(applyFeeAndTestResult(env, accum, feeTx1)));
BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx1));
accum.apply(*ledger);
}
@@ -655,8 +464,7 @@ class FeeVote_test : public beast::unit_test::suite
{
OpenView accum(ledger.get());
BEAST_EXPECT(
isTesSuccess(applyFeeAndTestResult(env, accum, feeTx2)));
BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx2));
accum.apply(*ledger);
}
@@ -669,7 +477,7 @@ class FeeVote_test : public beast::unit_test::suite
{
testcase("Wrong Ledger Sequence");
jtx::Env env(*this, jtx::testable_amendments() - featureSmartEscrow);
jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees);
auto ledger = std::make_shared<Ledger>(
create_genesis,
env.app().config(),
@@ -692,7 +500,7 @@ class FeeVote_test : public beast::unit_test::suite
// The transaction should still succeed as long as other fields are
// valid
// The ledger sequence field is only used for informational purposes
BEAST_EXPECT(isTesSuccess(applyFeeAndTestResult(env, accum, feeTx)));
BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx));
}
void
@@ -700,7 +508,7 @@ class FeeVote_test : public beast::unit_test::suite
{
testcase("Partial Field Updates");
jtx::Env env(*this, jtx::testable_amendments() - featureSmartEscrow);
jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees);
auto ledger = std::make_shared<Ledger>(
create_genesis,
env.app().config(),
@@ -718,8 +526,7 @@ class FeeVote_test : public beast::unit_test::suite
{
OpenView accum(ledger.get());
BEAST_EXPECT(
isTesSuccess(applyFeeAndTestResult(env, accum, feeTx1)));
BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx1));
accum.apply(*ledger);
}
@@ -736,8 +543,7 @@ class FeeVote_test : public beast::unit_test::suite
{
OpenView accum(ledger.get());
BEAST_EXPECT(
isTesSuccess(applyFeeAndTestResult(env, accum, feeTx2)));
BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx2));
accum.apply(*ledger);
}
@@ -750,7 +556,7 @@ class FeeVote_test : public beast::unit_test::suite
{
testcase("Single Invalid Transaction");
jtx::Env env(*this, jtx::testable_amendments() - featureSmartEscrow);
jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees);
auto ledger = std::make_shared<Ledger>(
create_genesis,
env.app().config(),
@@ -773,8 +579,7 @@ class FeeVote_test : public beast::unit_test::suite
});
OpenView accum(ledger.get());
BEAST_EXPECT(
!isTesSuccess(applyFeeAndTestResult(env, accum, invalidTx)));
BEAST_EXPECT(!applyFeeAndTestResult(env, accum, invalidTx));
}
void
@@ -791,7 +596,7 @@ class FeeVote_test : public beast::unit_test::suite
// Test with XRPFees enabled
{
Env env(*this, testable_amendments() - featureSmartEscrow);
Env env(*this, testable_amendments() | featureXRPFees);
auto feeVote = make_FeeVote(setup, env.app().journal("FeeVote"));
auto ledger = std::make_shared<Ledger>(
@@ -826,9 +631,7 @@ class FeeVote_test : public beast::unit_test::suite
// Test with XRPFees disabled (legacy format)
{
Env env(
*this,
testable_amendments() - featureXRPFees - featureSmartEscrow);
Env env(*this, testable_amendments() - featureXRPFees);
auto feeVote = make_FeeVote(setup, env.app().journal("FeeVote"));
auto ledger = std::make_shared<Ledger>(
@@ -871,7 +674,7 @@ class FeeVote_test : public beast::unit_test::suite
setup.account_reserve = 1234567;
setup.owner_reserve = 7654321;
Env env(*this, testable_amendments() - featureSmartEscrow);
Env env(*this, testable_amendments() | featureXRPFees);
// establish what the current fees are
BEAST_EXPECT(
@@ -961,128 +764,6 @@ class FeeVote_test : public beast::unit_test::suite
XRPAmount{setup.owner_reserve});
}
void
testDoVotingSmartEscrow()
{
testcase("doVoting with Smart Escrow");
using namespace jtx;
FeeSetup setup;
setup.reference_fee = 42;
setup.account_reserve = 1234567;
setup.owner_reserve = 7654321;
setup.extension_compute_limit = 100;
setup.extension_size_limit = 200;
setup.gas_price = 300;
Env env(
*this, testable_amendments() | featureXRPFees | featureSmartEscrow);
// establish what the current fees are
BEAST_EXPECT(
env.current()->fees().base == XRPAmount{UNIT_TEST_REFERENCE_FEE});
BEAST_EXPECT(env.current()->fees().reserve == XRPAmount{200'000'000});
BEAST_EXPECT(env.current()->fees().increment == XRPAmount{50'000'000});
BEAST_EXPECT(env.current()->fees().extensionComputeLimit == 0);
BEAST_EXPECT(env.current()->fees().extensionSizeLimit == 0);
BEAST_EXPECT(env.current()->fees().gasPrice == 0);
auto feeVote = make_FeeVote(setup, env.app().journal("FeeVote"));
auto ledger = std::make_shared<Ledger>(
create_genesis,
env.app().config(),
std::vector<uint256>{},
env.app().getNodeFamily());
// doVoting requires a flag ledger (every 256th ledger)
// We need to create a ledger at sequence 256 to make it a flag
// ledger
for (int i = 0; i < 256 - 1; ++i)
{
ledger = std::make_shared<Ledger>(
*ledger, env.app().timeKeeper().closeTime());
}
BEAST_EXPECT(ledger->isFlagLedger());
// Create some mock validations with fee votes
std::vector<std::shared_ptr<STValidation>> validations;
for (int i = 0; i < 5; i++)
{
auto sec = randomSecretKey();
auto pub = derivePublicKey(KeyType::secp256k1, sec);
auto val = std::make_shared<STValidation>(
env.app().timeKeeper().now(),
pub,
sec,
calcNodeID(pub),
[&](STValidation& v) {
v.setFieldU32(sfLedgerSequence, ledger->seq());
// Vote for different fees than current
v.setFieldAmount(
sfBaseFeeDrops, XRPAmount{setup.reference_fee});
v.setFieldAmount(
sfReserveBaseDrops, XRPAmount{setup.account_reserve});
v.setFieldAmount(
sfReserveIncrementDrops,
XRPAmount{setup.owner_reserve});
v.setFieldU32(
sfExtensionComputeLimit, setup.extension_compute_limit);
v.setFieldU32(
sfExtensionSizeLimit, setup.extension_size_limit);
v.setFieldU32(sfGasPrice, setup.gas_price);
});
if (i % 2)
val->setTrusted();
validations.push_back(val);
}
auto txSet = std::make_shared<SHAMap>(
SHAMapType::TRANSACTION, env.app().getNodeFamily());
// This should not throw since we have a flag ledger
feeVote->doVoting(ledger, validations, txSet);
auto const txs = getTxs(txSet);
BEAST_EXPECT(txs.size() == 1);
auto const& feeTx = txs[0];
BEAST_EXPECT(feeTx.getTxnType() == ttFEE);
BEAST_EXPECT(feeTx.getAccountID(sfAccount) == AccountID());
BEAST_EXPECT(feeTx.getFieldU32(sfLedgerSequence) == ledger->seq() + 1);
BEAST_EXPECT(feeTx.isFieldPresent(sfBaseFeeDrops));
BEAST_EXPECT(feeTx.isFieldPresent(sfReserveBaseDrops));
BEAST_EXPECT(feeTx.isFieldPresent(sfReserveIncrementDrops));
// The legacy fields should NOT be present
BEAST_EXPECT(!feeTx.isFieldPresent(sfBaseFee));
BEAST_EXPECT(!feeTx.isFieldPresent(sfReserveBase));
BEAST_EXPECT(!feeTx.isFieldPresent(sfReserveIncrement));
BEAST_EXPECT(!feeTx.isFieldPresent(sfReferenceFeeUnits));
// Check the values
BEAST_EXPECT(
feeTx.getFieldAmount(sfBaseFeeDrops) ==
XRPAmount{setup.reference_fee});
BEAST_EXPECT(
feeTx.getFieldAmount(sfReserveBaseDrops) ==
XRPAmount{setup.account_reserve});
BEAST_EXPECT(
feeTx.getFieldAmount(sfReserveIncrementDrops) ==
XRPAmount{setup.owner_reserve});
BEAST_EXPECT(
feeTx.getFieldU32(sfExtensionComputeLimit) ==
setup.extension_compute_limit);
BEAST_EXPECT(
feeTx.getFieldU32(sfExtensionSizeLimit) ==
setup.extension_size_limit);
BEAST_EXPECT(feeTx.getFieldU32(sfGasPrice) == setup.gas_price);
}
void
run() override
{
@@ -1096,7 +777,6 @@ class FeeVote_test : public beast::unit_test::suite
testSingleInvalidTransaction();
testDoValidation();
testDoVoting();
testDoVotingSmartEscrow();
}
};

View File

@@ -38,14 +38,14 @@ public:
auto const jtx = env.jt(ticket::create(alice, 1), seq(1), fee(10));
auto transactionId = jtx.stx->getTransactionID();
auto transacionId = jtx.stx->getTransactionID();
env.app().getHashRouter().setFlags(
transactionId, HashRouterFlags::HELD);
transacionId, HashRouterFlags::HELD);
env(jtx, json(jss::Sequence, 1), ter(terNO_ACCOUNT));
env.app().getHashRouter().setFlags(
transactionId, HashRouterFlags::BAD);
transacionId, HashRouterFlags::BAD);
env.close();
}

View File

@@ -33,12 +33,6 @@ 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) {
@@ -107,9 +101,7 @@ 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();
}

View File

@@ -715,6 +715,122 @@ struct Wasm_test : public beast::unit_test::suite
}
}
void
testWasmMemory()
{
testcase("Wasm additional memory limit tests");
auto& engine = WasmEngine::instance();
{
auto const ws = boost::algorithm::unhex(memoryPointerAtLimitHex);
Bytes const wasm(ws.begin(), ws.end());
auto const re = engine.run(wasm, "finish");
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECT(re->result == 1);
}
}
{
auto const ws = boost::algorithm::unhex(memoryPointerOverLimitHex);
Bytes const wasm(ws.begin(), ws.end());
auto const re = engine.run(wasm, "finish");
BEAST_EXPECT(!re.has_value());
}
{
auto const ws = boost::algorithm::unhex(memoryOffsetOverLimitHex);
Bytes const wasm(ws.begin(), ws.end());
auto const re = engine.run(wasm, "finish");
BEAST_EXPECT(!re.has_value());
}
{
auto const ws =
boost::algorithm::unhex(memoryEndOfWordOverLimitHex);
Bytes const wasm(ws.begin(), ws.end());
auto const re = engine.run(wasm, "finish");
BEAST_EXPECT(!re.has_value());
}
{
auto const ws = boost::algorithm::unhex(memoryGrow0To1PageHex);
Bytes const wasm(ws.begin(), ws.end());
auto const re = engine.run(wasm, "finish");
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECT(re->result == 1);
}
}
{
auto const ws = boost::algorithm::unhex(memoryLastByteOf8MBHex);
Bytes const wasm(ws.begin(), ws.end());
auto const re = engine.run(wasm, "finish");
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECT(re->result == 1);
}
}
{
auto const ws = boost::algorithm::unhex(memoryGrow1MoreThan8MBHex);
Bytes const wasm(ws.begin(), ws.end());
auto const re = engine.run(wasm, "finish");
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECT(re->result == -1);
}
}
}
void
testWasmTable()
{
testcase("Wasm table limit tests");
auto& engine = WasmEngine::instance();
{
auto const ws = boost::algorithm::unhex(table64ElementsHex);
Bytes const wasm(ws.begin(), ws.end());
auto const re = engine.run(wasm, "finish");
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECT(re->result == 1);
}
}
{
auto const ws = boost::algorithm::unhex(table65ElementsHex);
Bytes const wasm(ws.begin(), ws.end());
auto const re = engine.run(wasm, "finish");
BEAST_EXPECT(!re.has_value());
}
{
auto const ws = boost::algorithm::unhex(table2TablesHex);
Bytes const wasm(ws.begin(), ws.end());
auto const re = engine.run(wasm, "finish");
BEAST_EXPECT(!re.has_value());
}
}
void
testWasmProposal()
{
testcase("Wasm disabled proposal tests");
auto& engine = WasmEngine::instance();
{
auto const ws = boost::algorithm::unhex(proposalMutableGlobalHex);
Bytes const wasm(ws.begin(), ws.end());
auto const re = engine.run(wasm, "finish");
BEAST_EXPECT(!re.has_value());
}
}
void
testWasmTrap()
{
testcase("Wasm trap tests");
auto& engine = WasmEngine::instance();
{
auto const ws = boost::algorithm::unhex(divideBy0Hex);
Bytes const wasm(ws.begin(), ws.end());
auto const re = engine.run(wasm, "finish");
BEAST_EXPECT(!re.has_value());
}
}
void
run() override
{
@@ -736,6 +852,11 @@ struct Wasm_test : public beast::unit_test::suite
testCodecovWasm();
testDisabledFloat();
testWasmMemory();
testWasmTable();
testWasmProposal();
testWasmTrap();
// perfTest();
}
};

View File

@@ -1068,3 +1068,93 @@ extern std::string const disabledFloatHex =
"6503050b5f5f686561705f6261736503060a5f5f686561705f656e640307"
"0d5f5f6d656d6f72795f6261736503080c5f5f7461626c655f6261736503"
"090a150202000b100043000000c54300200045921a41010b";
extern std::string const memoryPointerAtLimitHex =
"0061736d010000000105016000017f030201000503010001070a010666696e69736800000a"
"0e010c0041ffff032d00001a41010b";
extern std::string const memoryPointerOverLimitHex =
"0061736d010000000105016000017f030201000503010001070a010666696e69736800000a"
"0e010c00418080042d00001a41010b";
extern std::string const memoryOffsetOverLimitHex =
"0061736d010000000105016000017f030201000503010001071302066d656d6f7279020006"
"66696e69736800000a0e010c00410028028080041a41010b";
extern std::string const memoryEndOfWordOverLimitHex =
"0061736d010000000105016000017f030201000503010001071302066d656d6f7279020006"
"66696e69736800000a0e010c0041feff032802001a41010b";
extern std::string const memoryGrow0To1PageHex =
"0061736d010000000105016000017f030201000503010000071302066d656d6f7279020006"
"66696e69736800000a0b010900410140001a41010b";
extern std::string const memoryLastByteOf8MBHex =
"0061736d010000000105016000017f030201000506010180018001071302066d656d6f7279"
"02000666696e69736800000a0f010d0041ffffff032d00001a41010b";
extern std::string const memoryGrow1MoreThan8MBHex =
"0061736d010000000105016000017f03020100050401008001071302066d656d6f72790200"
"0666696e69736800000a1301110041014000417f460440417f0f0b41010b";
extern std::string const table64ElementsHex =
"0061736d010000000108026000006000017f0303020001040401700040070a010666696e69"
"736800010946010041000b4000000000000000000000000000000000000000000000000000"
"00000000000000000000000000000000000000000000000000000000000000000000000000"
"00000a090202000b040041010b";
extern std::string const table65ElementsHex =
"0061736d010000000108026000006000017f0303020001040401700041070a010666696e69"
"736800010947010041000b4100000000000000000000000000000000000000000000000000"
"00000000000000000000000000000000000000000000000000000000000000000000000000"
"0000000a090202000b040041010b";
extern std::string const table2TablesHex =
"0061736d010000000108026000006000017f03030200010409027001010170010101070a01"
"0666696e6973680001090f020041000b0100020141000b0001000a090202000b040041010"
"b";
extern std::string const proposalMutableGlobalHex =
"0061736d010000000105016000017f030201000606017f0141000b07140207636f756e7465"
"7203000666696e69736800000a0d010b00230041016a240041010b";
extern std::string const divideBy0Hex =
"0061736d010000000105016000017f03020100070a010666696e69736800000a0c010a0041"
"2a41006d1a41010b";
extern std::string const hfParamSizeLimitHex =
"0061736d01000000011a0460027f7f017f60047f7f7f7f017f6000017f60037f7f7f017f02"
"370208686f73745f6c69620b7570646174655f64617461000008686f73745f6c696213636f"
"6d707574655f7368613531325f68616c660001030302020305030100100619037f01418080"
"c0000b7f00418080c0000b7f00418080c0000b072e04066d656d6f727902000666696e6973"
"6800020a5f5f646174615f656e6403010b5f5f686561705f6261736503020a820602d30201"
"057f23808080800041b0206b22002480808080002000410f6a41014180201083808080001a"
"02400240024002402000410f6a41802010808080800022014100480d002000410f6a410141"
"81201083808080001a2000410f6a41812010808080800022014174470d012000410f6a4101"
"4180081083808080001a200041a8206a22014200370300200041a0206a2202420037030020"
"004198206a2203420037030020004200370390202000410f6a41800820004190206a412010"
"818080800022044120470d022000410f6a41014181081083808080001a2001420037030020"
"02420037030020034200370300200042003703902002402000410f6a41810820004190206a"
"412010818080800022014174470d00410121010c040b200141e0606a21010c030b20014198"
"786a21010c020b200141b0706a21010c010b200441c8686a21010b200041b0206a24808080"
"800020010baa0301057f02400240200241104f0d00200021030c010b024020002000410020"
"006b41037122046a22054f0d002004417f6a21062000210302402004450d00200421072000"
"21030340200320013a0000200341016a21032007417f6a22070d000b0b20064107490d0003"
"40200320013a0000200341076a20013a0000200341066a20013a0000200341056a20013a00"
"00200341046a20013a0000200341036a20013a0000200341026a20013a0000200341016a20"
"013a0000200341086a22032005470d000b0b024020052005200220046b2202417c716a2203"
"4f0d00200141ff017141818284086c2107034020052007360200200541046a22052003490d"
"000b0b200241037121020b02402003200320026a22074f0d002002417f6a21040240200241"
"07712205450d000340200320013a0000200341016a21032005417f6a22050d000b0b200441"
"07490d000340200320013a0000200341076a20013a0000200341066a20013a000020034105"
"6a20013a0000200341046a20013a0000200341036a20013a0000200341026a20013a000020"
"0341016a20013a0000200341086a22032007470d000b0b20000b00c901046e616d65001817"
"68665f706172616d5f73697a655f746573742e7761736d01930104003b5f5a4e3136787270"
"6c5f7761736d5f7374646c696234686f737431317570646174655f64617461313768653132"
"366236373732633463656334614501435f5a4e31367872706c5f7761736d5f7374646c6962"
"34686f73743139636f6d707574655f7368613531325f68616c663137683837616334303364"
"656164316433306445020666696e69736803066d656d736574071201000f5f5f737461636b"
"5f706f696e746572004d0970726f64756365727302086c616e677561676501045275737400"
"0c70726f6365737365642d6279010572757374631d312e39302e3020283131353965373863"
"3420323032352d30392d31342900220f7461726765745f6665617475726573012b0f6d7574"
"61626c652d676c6f62616c73";

View File

@@ -27,3 +27,18 @@ extern std::string const floatTestsWasmHex;
extern std::string const float0Hex;
extern std::string const disabledFloatHex;
extern std::string const memoryPointerAtLimitHex;
extern std::string const memoryPointerOverLimitHex;
extern std::string const memoryOffsetOverLimitHex;
extern std::string const memoryEndOfWordOverLimitHex;
extern std::string const memoryGrow0To1PageHex;
extern std::string const memoryLastByteOf8MBHex;
extern std::string const memoryGrow1MoreThan8MBHex;
extern std::string const table64ElementsHex;
extern std::string const table65ElementsHex;
extern std::string const table2TablesHex;
extern std::string const proposalMutableGlobalHex;
extern std::string const divideBy0Hex;

View File

@@ -0,0 +1,15 @@
(module
(func $finish (export "finish") (result i32)
;; Setup for Requirement 2: Divide an i32 by 0
i32.const 42 ;; Push numerator
i32.const 0 ;; Push denominator (0)
i32.div_s ;; Perform signed division (42 / 0)
;; --- NOTE: Execution usually traps (crashes) at the line above ---
;; Logic to satisfy Requirement 1: Return i32 = 1
;; If execution continued, we would drop the division result and return 1
drop ;; Clear the stack
i32.const 1 ;; Push the return value
)
)

View File

@@ -0,0 +1,28 @@
(module
;; 1. Define Memory: 1 Page = 64KB = 65,536 bytes
(memory 1)
;; Export memory so the host can inspect it if needed
(export "memory" (memory 0))
(func $test_straddle (result i32)
;; Push the address onto the stack.
;; 65534 is valid, but it is only 2 bytes away from the end.
i32.const 65534
;; Attempt to load an i32 (4 bytes) from that address.
;; This requires bytes 65534, 65535, 65536, and 65537.
;; Since 65536 is the first invalid byte, this MUST trap.
i32.load
;; Clean up the stack.
;; The load pushed a value, but we don't care what it is.
drop
;; Return 1 to signal "I survived the memory access"
i32.const 1
)
;; Export the function so you can call it from your host (JS, Python, etc.)
(export "finish" (func $test_straddle))
)

View File

@@ -0,0 +1,26 @@
(module
;; 1. Define Memory: Start with 0 pages
(memory 0)
;; Export memory to host
(export "memory" (memory 0))
(func $grow_from_zero (result i32)
;; We have 0 pages. We want to add 1 page.
;; Push delta (1) onto stack.
i32.const 1
;; Grow the memory.
;; If successful: memory becomes 64KB, returns old size (0).
;; If failed: memory stays 0, returns -1.
memory.grow
;; Drop the return value of memory.grow
drop
;; Return 1 (as requested)
i32.const 1
)
(export "finish" (func $grow_from_zero))
)

View File

@@ -0,0 +1,26 @@
(module
;; Define memory: 128 pages (8MB) min, 128 pages max
(memory 128 128)
;; Export memory so host can verify size
(export "memory" (memory 0))
(func $access_last_byte (result i32)
;; Math: 128 pages * 64,536 bytes/page = 8,388,608 bytes
;; Valid indices: 0 to 8,388,607
;; Push the address of the LAST valid byte
i32.const 8388607
;; Load byte from that address
i32.load8_u
;; Drop the value (we don't care what it is, just that we could read it)
drop
;; Return 1 to indicate success
i32.const 1
)
(export "finish" (func $access_last_byte))
)

View File

@@ -0,0 +1,27 @@
(module
;; 1. Define Memory: 1 Page = 64KB
(memory 1)
(export "memory" (memory 0))
(func $test_offset_overflow (result i32)
;; 1. Push the base address onto the stack.
;; We use '0', which is the safest, most valid address possible.
i32.const 0
;; 2. Attempt to load using a static offset.
;; syntax: i32.load offset=N align=N
;; We set the offset to 65536 (the size of the memory).
;; The effective address becomes 0 + 65536 = 65536.
i32.load offset=65536
;; Clean up the stack.
;; The load pushed a value, but we don't care what it is.
drop
;; Return 1 to signal "I survived the memory access"
i32.const 1
)
(export "finish" (func $test_offset_overflow))
)

View File

@@ -0,0 +1,29 @@
(module
;; Start at your limit: 128 pages (8MB)
(memory 128)
(export "memory" (memory 0))
(func $try_grow_beyond_limit (result i32)
;; Attempt to grow by 1 page
i32.const 1
memory.grow
;; memory.grow returns:
;; -1 if the growth failed (Correct behavior for your limit)
;; 128 (old size) if growth succeeded (Means limit was bypassed)
;; Check if result == -1
i32.const -1
i32.eq
if
;; Growth FAILED (Host blocked it). Return -1.
i32.const -1
return
end
;; Growth SUCCEEDED (Host allowed it). Return 1.
i32.const 1
)
(export "finish" (func $try_grow_beyond_limit))
)

View File

@@ -0,0 +1,22 @@
(module
;; Define 1 page of memory (64KB = 65,536 bytes)
(memory 1)
(func $read_edge (result i32)
;; Push the index of the LAST valid byte
i32.const 65535
;; Load 1 byte (unsigned)
i32.load8_u
;; Clean up the stack.
;; The load pushed a value, but we don't care what it is.
drop
;; Return 1 to signal "I survived the memory access"
i32.const 1
)
;; Export as "finish" as requested
(export "finish" (func $read_edge))
)

View File

@@ -0,0 +1,23 @@
(module
;; Define 1 page of memory (64KB = 65,536 bytes)
(memory 1)
(func $read_overflow (result i32)
;; Push the index of the FIRST invalid byte
;; Memory is 0..65535, so 65536 is out of bounds.
i32.const 65536
;; Load 1 byte (unsigned)
i32.load8_u
;; Clean up the stack.
;; The load pushed a value, but we don't care what it is.
drop
;; Return 1 to signal "I survived the memory access"
i32.const 1
)
;; Export as "finish" as requested
(export "finish" (func $read_overflow))
)

View File

@@ -0,0 +1,25 @@
(module
;; Define a mutable global initialized to 0
(global $counter (mut i32) (i32.const 0))
;; EXPORTING a mutable global is the key feature of this proposal.
;; In strict MVP, exported globals had to be immutable (const).
(export "counter" (global $counter))
(func $finish (result i32)
;; 1. Get current value
global.get $counter
;; 2. Add 1
i32.const 1
i32.add
;; 3. Set new value (Mutation)
global.set $counter
;; 4. Return 1 for success
i32.const 1
)
(export "finish" (func $finish))
)

View File

@@ -0,0 +1 @@
;;hard to generate

View File

@@ -0,0 +1,24 @@
(module
;; Define a dummy function to put in the tables
(func $dummy)
;; TABLE 0: The default table (allowed in MVP)
;; Size: 1 initial, 1 max
(table $t0 1 1 funcref)
;; Initialize Table 0 at index 0
(elem (table $t0) (i32.const 0) $dummy)
;; TABLE 1: The second table (Requires Reference Types proposal)
;; If strict MVP is enforced, the parser should error here.
(table $t1 1 1 funcref)
;; Initialize Table 1 at index 0
(elem (table $t1) (i32.const 0) $dummy)
(func $finish (result i32)
;; If we successfully loaded a module with 2 tables, return 1.
i32.const 1
)
(export "finish" (func $finish))
)

View File

@@ -0,0 +1,25 @@
(module
;; Define a table with exactly 64 entries
(table 64 funcref)
;; A dummy function to reference
(func $dummy)
;; Initialize the table at offset 0 with 64 references to $dummy
(elem (i32.const 0)
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 8
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 16
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 24
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 32
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 40
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 48
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 56
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 64
)
;; Standard finish function
(func $finish (result i32)
i32.const 1
)
(export "finish" (func $finish))
)

View File

@@ -0,0 +1,25 @@
(module
;; Define a table with exactly 65 entries
(table 65 funcref)
;; A dummy function to reference
(func $dummy)
;; Initialize the table at offset 0 with 65 references to $dummy
(elem (i32.const 0)
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 8
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 16
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 24
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 32
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 40
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 48
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 56
$dummy $dummy $dummy $dummy $dummy $dummy $dummy $dummy ;; 64
$dummy ;; 65 (The one that breaks the camel's back)
)
(func $finish (result i32)
i32.const 1
)
(export "finish" (func $finish))
)

View File

@@ -515,22 +515,6 @@ 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;
};
@@ -1595,8 +1579,7 @@ public:
testTransactions_APIv1();
testTransactions_APIv2();
testManifests();
testValidations(all - featureXRPFees - featureSmartEscrow);
testValidations(all - featureSmartEscrow);
testValidations(all - xrpFees);
testValidations(all);
testSubErrors(true);
testSubErrors(false);

View File

@@ -202,15 +202,6 @@ 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);
}
@@ -604,7 +595,6 @@ Ledger::setup()
{
bool oldFees = false;
bool newFees = false;
bool extensionFees = false;
{
auto const baseFee = sle->at(~sfBaseFee);
auto const reserveBase = sle->at(~sfReserveBase);
@@ -622,7 +612,6 @@ Ledger::setup()
auto const reserveBaseXRP = sle->at(~sfReserveBaseDrops);
auto const reserveIncrementXRP =
sle->at(~sfReserveIncrementDrops);
auto assign = [&ret](
XRPAmount& dest,
std::optional<STAmount> const& src) {
@@ -639,35 +628,12 @@ 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&)
@@ -686,23 +652,15 @@ Ledger::setup()
void
Ledger::defaultFees(Config const& config)
{
assert(
fees_.base == 0 && fees_.reserve == 0 && fees_.increment == 0 &&
fees_.extensionComputeLimit == 0 && fees_.extensionSizeLimit == 0 &&
fees_.gasPrice == 0);
XRPL_ASSERT(
fees_.base == 0 && fees_.reserve == 0 && fees_.increment == 0,
"ripple::Ledger::defaultFees : zero fees");
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>

View File

@@ -9,10 +9,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_;
@@ -47,9 +47,8 @@ public:
getVotes() const;
};
template <typename value_type>
std::pair<value_type, bool>
VotableValue<value_type>::getVotes() const
auto
VotableValue::getVotes() const -> std::pair<value_type, bool>
{
value_type ourVote = current_;
int weight = 0;
@@ -172,33 +171,6 @@ 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
@@ -221,22 +193,11 @@ 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<XRPAmount>& value,
detail::VotableValue& value,
SF_AMOUNT const& xrpField) {
if (auto const field = ~val->at(~xrpField);
field && field->native())
@@ -265,7 +226,7 @@ FeeVoteImpl::doVoting(
else
{
auto doVote = [](std::shared_ptr<STValidation> const& val,
detail::VotableValue<XRPAmount>& value,
detail::VotableValue& value,
auto const& valueField) {
if (auto const field = val->at(~valueField))
{
@@ -296,30 +257,6 @@ 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
@@ -328,15 +265,11 @@ 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 ||
extensionCompute.second || extensionSize.second || gasPrice.second)
if (baseFee.second || baseReserve.second || incReserve.second)
{
JLOG(journal_.warn())
<< "We are voting for a fee change: " << baseFee.first << "/"
@@ -364,12 +297,6 @@ 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();

View File

@@ -2464,18 +2464,6 @@ 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};
@@ -2925,20 +2913,11 @@ 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 =
lpClosed->rules().enabled(featureSmartEscrow);
if (!human)
{
l[jss::base_fee] = baseFee.jsonClipped();
l[jss::reserve_base] = lpClosed->fees().reserve.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());
}
@@ -2947,13 +2926,6 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters)
l[jss::base_fee_xrp] = baseFee.decimalXRP();
l[jss::reserve_base_xrp] = lpClosed->fees().reserve.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)
@@ -3145,14 +3117,6 @@ NetworkOPsImp::pubLedger(std::shared_ptr<ReadView const> const& lpAccepted)
jvObj[jss::reserve_base] = lpAccepted->fees().reserve.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());
@@ -3523,8 +3487,8 @@ NetworkOPsImp::pubAccountTransaction(
}
JLOG(m_journal.trace())
<< "pubAccountTransaction: " << "proposed=" << iProposed
<< ", accepted=" << iAccepted;
<< "pubAccountTransaction: "
<< "proposed=" << iProposed << ", accepted=" << iAccepted;
if (!notify.empty() || !accountHistoryNotify.empty())
{
@@ -4225,19 +4189,12 @@ 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().reserve.jsonClipped();
jvResult[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
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;
}
jvResult[jss::network_id] = app_.config().NETWORK_ID;
}
if ((mMode >= OperatingMode::SYNCING) && !isNeedNetworkLedger())

View File

@@ -105,20 +105,6 @@ 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:
@@ -283,12 +269,6 @@ 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);

View File

@@ -54,15 +54,6 @@ 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.) */
};

View File

@@ -1122,12 +1122,6 @@ 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;
}