Compare commits

...

6 Commits

Author SHA1 Message Date
Denis Angell
0bb9465f7d [fold] fix asserts 2025-02-01 13:42:27 +01:00
Denis Angell
587fe993a2 [fold] clang-format 2025-02-01 09:09:24 +01:00
Denis Angell
b512d7f469 Merge branch 'dev' into fix20250131 2025-02-01 09:07:04 +01:00
Richard Holland
2e624c8253 add some documentation to the ruleVersion in check_guard 2025-02-01 17:41:25 +11:00
Richard Holland
a071c592b7 additional fix 2025-02-01 16:53:46 +11:00
Richard Holland
e0308e021b fix20250131 2025-01-31 19:04:18 +11:00
10 changed files with 103 additions and 9 deletions

View File

@@ -3,6 +3,7 @@
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <memory> #include <memory>
#include <optional>
#include <ostream> #include <ostream>
#include <stack> #include <stack>
#include <string> #include <string>
@@ -271,7 +272,19 @@ check_guard(
int guard_func_idx, int guard_func_idx,
int last_import_idx, int last_import_idx,
GuardLog guardLog, GuardLog guardLog,
std::string guardLogAccStr) std::string guardLogAccStr,
/* RH NOTE:
* rules version is a bit field, so rule update 1 is 0x01, update 2 is 0x02
* and update 3 is 0x04 ideally at rule version 3 all bits so far are set
* (0b111) so the ruleVersion = 7, however if a specific rule update must be
* rolled back due to unforeseen behaviour then this may no longer be the
* case. using a bit field here leaves us flexible to rollback changes that
* might have unforeseen consequences, without also rolling back further
* changes that are fine.
*/
uint64_t rulesVersion = 0
)
{ {
#define MAX_GUARD_CALLS 1024 #define MAX_GUARD_CALLS 1024
uint32_t guard_count = 0; uint32_t guard_count = 0;
@@ -621,11 +634,17 @@ check_guard(
} }
else if (fc_type == 10) // memory.copy else if (fc_type == 10) // memory.copy
{ {
if (rulesVersion & 0x02U)
GUARD_ERROR("Memory.copy instruction is not allowed.");
REQUIRE(2); REQUIRE(2);
ADVANCE(2); ADVANCE(2);
} }
else if (fc_type == 11) // memory.fill else if (fc_type == 11) // memory.fill
{ {
if (rulesVersion & 0x02U)
GUARD_ERROR("Memory.fill instruction is not allowed.");
ADVANCE(1); ADVANCE(1);
} }
else if (fc_type <= 7) // numeric instructions else if (fc_type <= 7) // numeric instructions
@@ -807,6 +826,15 @@ validateGuards(
std::vector<uint8_t> const& wasm, std::vector<uint8_t> const& wasm,
GuardLog guardLog, GuardLog guardLog,
std::string guardLogAccStr, std::string guardLogAccStr,
/* RH NOTE:
* rules version is a bit field, so rule update 1 is 0x01, update 2 is 0x02
* and update 3 is 0x04 ideally at rule version 3 all bits so far are set
* (0b111) so the ruleVersion = 7, however if a specific rule update must be
* rolled back due to unforeseen behaviour then this may no longer be the
* case. using a bit field here leaves us flexible to rollback changes that
* might have unforeseen consequences, without also rolling back further
* changes that are fine.
*/
uint64_t rulesVersion = 0) uint64_t rulesVersion = 0)
{ {
uint64_t byteCount = wasm.size(); uint64_t byteCount = wasm.size();
@@ -1477,7 +1505,8 @@ validateGuards(
guard_import_number, guard_import_number,
last_import_number, last_import_number,
guardLog, guardLog,
guardLogAccStr); guardLogAccStr,
rulesVersion);
if (!valid) if (!valid)
return {}; return {};

View File

@@ -79,7 +79,7 @@ main(int argc, char** argv)
close(fd); close(fd);
auto result = validateGuards(hook, std::cout, "", 1); auto result = validateGuards(hook, std::cout, "", 3);
if (!result) if (!result)
{ {

View File

@@ -587,7 +587,8 @@ Change::activateXahauGenesis()
wasmBytes, // wasm to verify wasmBytes, // wasm to verify
loggerStream, loggerStream,
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
ctx_.view().rules().enabled(featureHooksUpdate1) ? 1 : 0); (ctx_.view().rules().enabled(featureHooksUpdate1) ? 1 : 0) +
(ctx_.view().rules().enabled(fix20250131) ? 2 : 0));
if (!result) if (!result)
{ {

View File

@@ -72,6 +72,16 @@ Remit::preflight(PreflightContext const& ctx)
return temREDUNDANT; return temREDUNDANT;
} }
if (ctx.rules.enabled(fix20250131))
{
if (!dstID || dstID == noAccount())
{
JLOG(ctx.j.warn())
<< "Malformed transaction: Remit to invalid account.";
return temMALFORMED;
}
}
if (ctx.tx.isFieldPresent(sfInform)) if (ctx.tx.isFieldPresent(sfInform))
{ {
AccountID const infID = ctx.tx.getAccountID(sfInform); AccountID const infID = ctx.tx.getAccountID(sfInform);

View File

@@ -479,7 +479,8 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj)
hook, // wasm to verify hook, // wasm to verify
logger, logger,
hsacc, hsacc,
ctx.rules.enabled(featureHooksUpdate1) ? 1 : 0); (ctx.rules.enabled(featureHooksUpdate1) ? 1 : 0) +
(ctx.rules.enabled(fix20250131) ? 2 : 0));
if (ctx.j.trace()) if (ctx.j.trace())
{ {

View File

@@ -74,7 +74,7 @@ namespace detail {
// Feature.cpp. Because it's only used to reserve storage, and determine how // Feature.cpp. Because it's only used to reserve storage, and determine how
// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than // large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
// the actual number of amendments. A LogicError on startup will verify this. // the actual number of amendments. A LogicError on startup will verify this.
static constexpr std::size_t numFeatures = 76; static constexpr std::size_t numFeatures = 77;
/** Amendments that this server supports and the default voting behavior. /** Amendments that this server supports and the default voting behavior.
Whether they are enabled depends on the Rules defined in the validated Whether they are enabled depends on the Rules defined in the validated
@@ -364,6 +364,7 @@ extern uint256 const fix240911;
extern uint256 const fixFloatDivide; extern uint256 const fixFloatDivide;
extern uint256 const fixReduceImport; extern uint256 const fixReduceImport;
extern uint256 const fixXahauV3; extern uint256 const fixXahauV3;
extern uint256 const fix20250131;
} // namespace ripple } // namespace ripple

View File

@@ -469,7 +469,8 @@ REGISTER_FIX (fixPageCap, Supported::yes, VoteBehavior::De
REGISTER_FIX (fix240911, Supported::yes, VoteBehavior::DefaultYes); REGISTER_FIX (fix240911, Supported::yes, VoteBehavior::DefaultYes);
REGISTER_FIX (fixFloatDivide, Supported::yes, VoteBehavior::DefaultYes); REGISTER_FIX (fixFloatDivide, Supported::yes, VoteBehavior::DefaultYes);
REGISTER_FIX (fixReduceImport, Supported::yes, VoteBehavior::DefaultYes); REGISTER_FIX (fixReduceImport, Supported::yes, VoteBehavior::DefaultYes);
REGISTER_FIX (fixXahauV3, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX (fixXahauV3, Supported::yes, VoteBehavior::DefaultYes);
REGISTER_FIX (fix20250131, Supported::yes, VoteBehavior::DefaultYes);
// The following amendments are obsolete, but must remain supported // The following amendments are obsolete, but must remain supported
// because they could potentially get enabled. // because they could potentially get enabled.

View File

@@ -240,7 +240,9 @@ TxMeta::addRaw(Serializer& s, TER result, std::uint32_t index)
{ {
mResult = TERtoInt(result); mResult = TERtoInt(result);
mIndex = index; mIndex = index;
assert((mResult == 0) || ((mResult > 100) && (mResult <= 255))); assert(
(mResult == 0 || mResult == 1) ||
((mResult > 100) && (mResult <= 255)));
mNodes.sort([](STObject const& o1, STObject const& o2) { mNodes.sort([](STObject const& o1, STObject const& o2) {
return o1.getFieldH256(sfLedgerIndex) < o2.getFieldH256(sfLedgerIndex); return o1.getFieldH256(sfLedgerIndex) < o2.getFieldH256(sfLedgerIndex);

View File

@@ -5544,7 +5544,6 @@ public:
testTSH(sa - fixXahauV1 - fixXahauV2); testTSH(sa - fixXahauV1 - fixXahauV2);
testTSH(sa - fixXahauV2); testTSH(sa - fixXahauV2);
testTSH(sa); testTSH(sa);
testEmittedTxn(sa - fixXahauV2);
testEmittedTxn(sa); testEmittedTxn(sa);
} }
}; };

View File

@@ -1138,6 +1138,54 @@ public:
: preHookCount + 66); : preHookCount + 66);
} }
void
testFillCopy(FeatureBitset features)
{
testcase("Test fill/copy");
// a hook containing memory.fill instruction
std::string hookFill =
"0061736d0100000001130360027f7f017f60037f7f7e017e60017f017e02"
"170203656e76025f67000003656e76066163636570740001030201020503"
"0100020621057f01418088040b7f004180080b7f004180080b7f00418088"
"040b7f004180080b07080104686f6f6b00020aa4800001a0800001017e23"
"01412a41e400fc0b004101410110001a41004100420010011a20010b";
// a hook containing memory.copy instruction
std::string hookCopy =
"0061736d0100000001130360027f7f017f60037f7f7e017e60017f017e02"
"170203656e76025f67000003656e76066163636570740001030201020503"
"0100020621057f01418088040b7f004180080b7f004180080b7f00418088"
"040b7f004180080b07080104686f6f6b00020aa5800001a1800001017e23"
"00230141e400fc0a00004101410110001a41004100420010011a20010b";
using namespace jtx;
for (int withFix = 0; withFix < 2; ++withFix)
{
auto f = withFix ? features : features - fix20250131;
Env env{*this, f};
auto const alice = Account{"alice"};
env.fund(XRP(10000), alice);
auto const bob = Account{"bob"};
env.fund(XRP(10000), bob);
env(ripple::test::jtx::hook(alice, {{hso(hookFill)}}, 0),
M(withFix ? "hookFill - with fix" : "hookFill - zonder fix"),
HSFEE,
withFix ? ter(temMALFORMED) : ter(tesSUCCESS));
env(ripple::test::jtx::hook(bob, {{hso(hookCopy)}}, 0),
M(withFix ? "hookCopy - with fix" : "hookCopy - zonder fix"),
HSFEE,
withFix ? ter(temMALFORMED) : ter(tesSUCCESS));
env.close();
}
}
void void
testCreate(FeatureBitset features) testCreate(FeatureBitset features)
{ {
@@ -11973,6 +12021,8 @@ public:
testNSDeletePartial(features); testNSDeletePartial(features);
testPageCap(features); testPageCap(features);
testFillCopy(features);
testWasm(features); testWasm(features);
test_accept(features); test_accept(features);
test_rollback(features); test_rollback(features);