Compare commits

..

8 Commits

Author SHA1 Message Date
tequ
8f244d888d Merge remote-tracking branch 'upstream/sync-2.4.0' into HookAPISerializedType240 2026-02-18 10:39:29 +09:00
tequ
3c49f80013 Add new keylets to util_keylet (#533) 2026-02-18 11:18:59 +10:00
Niq Dudfield
090e4ad25e Merge dev (309e517e7) into sync-2.4.0: docs + guard checker CI (#683)
* Hook API Refactor2: Amendment Guards (#621)

* Hook API Refactor3: Consolidate the Hook API definitions from Enum.h and ApplyHook.h into a single file. (#622)

* Hook API Refactoring / Unit Testing (#581)

* fix `Xahau Ledger` to `Xahau Network` (#651)

* Add GitHub Actions workflow for Guard Checker Build (#658)

* fix `Xahau Ledger` to `Xahau Network` (#651)

* Add GitHub Actions workflow for Guard Checker Build (#658)

* fix: update guard checker build path for directory restructure

* fix: update stale ripple include paths in hook headers

* fix(test): avoid deleted PublicKey default ctor in HookAPI test

* chore(levelization): update ordering after hook/protocol dependency change

---------

Co-authored-by: tequ <git@tequ.dev>
2026-02-18 11:17:27 +10:00
tequ
01e7ee4f03 fix: update comment for HookParameterValue size limit 2026-01-06 23:17:43 +09:00
tequ
222772d99b fix get_stobject_length to work STI_PATHSET correctly 2026-01-06 23:14:47 +09:00
tequ
9e6135ba42 refactor get_stobject_length 2026-01-06 20:21:12 +09:00
tequ
f0329b4054 Merge branch 'dev' into HookAPISerializedType240 2026-01-06 18:21:01 +09:00
tequ
5a9baed9d0 HookAPISerializedType240 Amendment 2025-12-17 19:39:31 +09:00
9 changed files with 1676 additions and 753 deletions

View File

@@ -300,7 +300,17 @@ enum keylet_code : uint32_t {
NFT_OFFER = 23,
HOOK_DEFINITION = 24,
HOOK_STATE_DIR = 25,
CRON = 26
CRON = 26,
AMM = 27,
BRIDGE = 28,
XCHAIN_OWNED_CLAIM_ID = 29,
XCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID = 30,
DID = 31,
ORACLE = 32,
MPTOKEN_ISSUANCE = 33,
MPTOKEN = 34,
CREDENTIAL = 35,
PERMISSIONED_DOMAIN = 36,
};
}

View File

@@ -329,14 +329,15 @@ private:
int32_t,
parse_error>
get_stobject_length(
unsigned char* start, // in - begin iterator
unsigned char* maxptr, // in - end iterator
int& type, // out - populated by serialized type code
int& field, // out - populated by serialized field code
int& payload_start, // out - the start of actual payload data for
// this type
int& payload_length, // out - the length of actual payload data for
// this type
unsigned char* start, // in - begin iterator
unsigned char* maxptr, // in - end iterator
int& type, // out - populated by serialized type code
int& field, // out - populated by serialized field code
int& payload_start, // out - the start of actual payload data for
// this type
int& payload_length, // out - the length of actual payload data for
// this type
Rules const& rules,
int recursion_depth = 0) // used internally
const;
};

View File

@@ -80,7 +80,7 @@ namespace detail {
// 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
// the actual number of amendments. A LogicError on startup will verify this.
static constexpr std::size_t numFeatures = 110;
static constexpr std::size_t numFeatures = 111;
/** Amendments that this server supports and the default voting behavior.
Whether they are enabled depends on the Rules defined in the validated

View File

@@ -29,6 +29,7 @@
// If you add an amendment here, then do not forget to increment `numFeatures`
// in include/xrpl/protocol/Feature.h.
XRPL_FEATURE(HookAPISerializedType240, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(PermissionedDomains, Supported::no, VoteBehavior::DefaultNo)
XRPL_FEATURE(DynamicNFT, Supported::no, VoteBehavior::DefaultNo)
XRPL_FEATURE(Credentials, Supported::no, VoteBehavior::DefaultNo)

View File

@@ -487,7 +487,7 @@ isMemoOkay(STObject const& st, std::string& reason)
if (!paramObj->isFieldPresent(sfHookParameterValue) ||
paramObj->getFieldVL(sfHookParameterValue).size() > maxVal)
{
reason = "HookParameterValue cannot exceed 128 bytes.";
reason = "HookParameterValue cannot exceed 256 bytes.";
return false;
}
}

View File

@@ -10951,6 +10951,186 @@ public:
// invoke the hook
env(pay(bob, alice, XRP(1)), M("test sto_validate"), fee(XRP(1)));
{
// test STIs
TestHook hook = wasm[R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
#define GUARD(maxiter) _g((1ULL << 31U) + __LINE__, (maxiter)+1)
extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
extern int64_t rollback (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
extern int64_t sto_validate(uint32_t, uint32_t);
extern int64_t otxn_param(uint32_t, uint32_t, uint32_t, uint32_t);
#define ASSERT(x)\
if (!(x))\
rollback((uint32_t)#x, sizeof(#x), __LINE__);
#define SBUF(x) (uint32_t)(x), sizeof(x)
uint8_t buf[1000];
int64_t hook(uint32_t reserved)
{
_g(1,1);
int64_t size = otxn_param(SBUF(buf), "V", 1);
int64_t result = sto_validate(buf, size);
accept(0,0,result);
}
)[test.hook]"];
for (auto feature : {
features - featureHookAPISerializedType240,
features | featureHookAPISerializedType240,
})
{
Env env{*this, feature};
env.fund(XRP(10000), alice, bob);
env.close();
auto hasEnabled = env.current()->rules().enabled(
featureHookAPISerializedType240);
// install the hook on alice
env(ripple::test::jtx::hook(
alice, {{hso(hook, overrideFlag)}}, 0),
M("set sto_validate"),
HSFEE);
env.close();
// invoke the hook
auto buildTx = [&](std::string value) {
auto payJv = pay(bob, alice, XRP(1));
Json::Value params{Json::arrayValue};
auto& param = params[0U][jss::HookParameter];
param[jss::HookParameterName] = strHex(std::string("V"));
param[jss::HookParameterValue] = value;
payJv[jss::HookParameters] = params;
return payJv;
};
auto testSTI = [&](std::string value, bool expectedResult) {
auto tx = buildTx(value);
env(tx, M("test STI"), fee(XRP(1)));
env.close();
auto const result = env.meta()
->getFieldArray(sfHookExecutions)[0]
.getFieldU64(sfHookReturnCode);
if (expectedResult)
BEAST_EXPECTS(result == 1, value);
else
BEAST_EXPECTS(result == 0, value);
};
// STI_UINT32
testSTI("2200000001", true);
// STI_UINT64
testSTI("301100000000000003E8", true);
// STI_UINT128
testSTI("4100000000000000000000000000000000", true);
// STI_UINT256
testSTI(
"5060000000000000000000000000000000000000000000000000000000"
"0000000000",
true);
// STI_AMOUNT
testSTI("614000000000000064", true);
testSTI(
"61D5038D7EA4C680000000000000000000000000005553440000000000"
"AE123A8556F3CF91154711376AFB0F894F832B3D",
true);
// STI_VL
testSTI("7504DEADBEEF", true);
// STI_ACCOUNT
testSTI("8114AE123A8556F3CF91154711376AFB0F894F832B3D", true);
// STI_NUMBER
// testSTI("000400000000000000000000000000000001", true);
// STI_OBJECT
testSTI("E05C22000000017504DEADBEEFE1", true);
// STI_ARRAY
testSTI(
"F05CE05B614000000000000064E1E05B61D5038D7EA4C6800000000000"
"00000000000000005553440000000000AE123A8556F3CF91154711376A"
"FB0F894F832B3DE1F1",
true);
// STI_UINT8
testSTI("00101003", true);
// STI_UINT160
testSTI("01110000000000000000000000000000000000000000", true);
// STI_PATHSET
testSTI(
"0112300000000000000000000000005553440000000000AE123A8556F3"
"CF91154711376AFB0F894F832B3D00",
hasEnabled);
testSTI(
"0112310A20B3C85F482532A9578DBB3950B85CA06594D1000000000000"
"00000000000042544300000000000A20B3C85F482532A9578DBB3950B8"
"5CA06594D13000000000000000000000000055534400000000000A20B3"
"C85F482532A9578DBB3950B85CA06594D1FF3157180C769B66D942EE69"
"E6DCC940CA48D82337AD00000000000000000000000042544300000000"
"0057180C769B66D942EE69E6DCC940CA48D82337AD1000000000000000"
"0000000000000000000000000030000000000000000000000000555344"
"00000000000A20B3C85F482532A9578DBB3950B85CA06594D100",
hasEnabled);
// STI_VECTOR256
testSTI(
"0013634000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000"
"00000000000000000000",
true);
// STI_UINT96
// testSTI("000400000000000000000000000000000001", true);
// STI_UINT192
// testSTI("000400000000000000000000000000000001", true);
// STI_UINT384
// testSTI("000400000000000000000000000000000001", true);
// STI_UINT512
// testSTI("000400000000000000000000000000000001", true);
// STI_ISSUE
testSTI(
"03180000000000000000000000005553440000000000AE123A8556F3CF"
"91154711376AFB0F894F832B3D",
hasEnabled);
testSTI(
"03180000000000000000000000000000000000000000", hasEnabled);
// STI_XCHAIN_BRIDGE
/// Native-Native
testSTI(
"011914AE123A8556F3CF91154711376AFB0F894F832B3D000000000000"
"000000000000000000000000000014AE123A8556F3CF91154711376AFB"
"0F894F832B3D0000000000000000000000000000000000000000",
hasEnabled);
/// IOU-Native
testSTI(
"011914AE123A8556F3CF91154711376AFB0F894F832B3D000000000000"
"0000000000005553440000000000AE123A8556F3CF91154711376AFB0F"
"894F832B3D14AE123A8556F3CF91154711376AFB0F894F832B3D000000"
"0000"
"000000000000000000000000000000",
hasEnabled);
/// Native-IOU
testSTI(
"011914AE123A8556F3CF91154711376AFB0F894F832B3D000000000000"
"0000000000005553440000000000AE123A8556F3CF91154711376AFB0F"
"894F832B3D14AE123A8556F3CF91154711376AFB0F894F832B3D000000"
"0000000000000000000000000000000000",
hasEnabled);
/// IOU-IOU
testSTI(
"011914AE123A8556F3CF91154711376AFB0F894F832B3D000000000000"
"0000000000005553440000000000AE123A8556F3CF91154711376AFB0F"
"894F832B3D14AE123A8556F3CF91154711376AFB0F894F832B3D000000"
"0000000000000000005553440000000000AE123A8556F3CF9115471137"
"6AFB0F894F832B3D",
hasEnabled);
// STI_CURRENCY
testSTI(
"011A0000000000000000000000005553440000000000", hasEnabled);
}
}
}
void
@@ -11414,7 +11594,19 @@ public:
#define KEYLET_PAYCHAN 21
#define KEYLET_EMITTED_TXN 22
#define KEYLET_NFT_OFFER 23
#define KEYLET_HOOK_DEFINITION 24
#define KEYLET_HOOK_STATE_DIR 25
#define KEYLET_CRON 26
#define KEYLET_AMM 27
#define KEYLET_BRIDGE 28
#define KEYLET_XCHAIN_OWNED_CLAIM_ID 29
#define KEYLET_XCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID 30
#define KEYLET_DID 31
#define KEYLET_ORACLE 32
#define KEYLET_MPTOKEN_ISSUANCE 33
#define KEYLET_MPTOKEN 34
#define KEYLET_CREDENTIAL 35
#define KEYLET_PERMISSIONED_DOMAIN 36
#define ASSERT(x)\
if (!(x))\
rollback((uint32_t)#x, sizeof(#x), __LINE__);
@@ -11462,6 +11654,22 @@ public:
0x3AU,0x51U,0x8AU,0x22U,0x53U,0x81U,0x60U,0x84U,0x1CU,0x14U,0x32U,0xFEU,
0x6FU,0x3EU,0x6DU,0x6EU,0x76U,0x29U,0xFBU,0xBAU
};
uint8_t asset1[] = // USD.rB6v18pQ765Z9DH5RQsTFevoQPFmRtBqhT
{
0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,
0x00U,0x00U,0x55U,0x53U,0x44U,0x00U,0x00U,0x00U,0x00U,0x00U,
0x75U,0x6EU,0xDEU,0x88U,0xA9U,0x07U,0xD4U,0xCCU,0xF3U,0x8DU,0x6AU,0xDBU,
0x9FU,0xC7U,0x94U,0x64U,0x19U,0xF0U,0xC4U,0x1DU
};
uint8_t asset2[] = // EUR.raKM1bZkGmASBqN5v2swrf2uAPJ32Cd8GV
{
0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,
0x00U,0x00U,0x45U,0x48U,0x52U,0x00U,0x00U,0x00U,0x00U,0x00U,
0x3AU,0x51U,0x8AU,0x22U,0x53U,0x81U,0x60U,0x84U,0x1CU,0x14U,0x32U,0xFEU,
0x6FU,0x3EU,0x6DU,0x6EU,0x76U,0x29U,0xFBU,0xBAU
};
int64_t hook(uint32_t reserved )
{
@@ -11916,11 +12124,76 @@ public:
0,0
)));
ASSERT(34 == (e=util_keylet(buf, 34, KEYLET_NFT_OFFER,
SBUF(a), SBUF(ns),
0,0
)));
ASSERT(34 == (e=util_keylet(buf, 34, KEYLET_HOOK_DEFINITION,
SBUF(ns),
0,0,
0,0
)));
ASSERT(34 == (e=util_keylet(buf, 34, KEYLET_HOOK_STATE_DIR,
SBUF(a), SBUF(ns),
0,0
)));
ASSERT(34 == (e=util_keylet(buf, 34, KEYLET_AMM,
SBUF(asset1), SBUF(asset2),
0,0
)));
ASSERT(INVALID_ARGUMENT == (e=util_keylet(buf, 34, KEYLET_BRIDGE,
SBUF(a), SBUF(b),
0,0
)));
ASSERT(INVALID_ARGUMENT == (e=util_keylet(buf, 34, KEYLET_XCHAIN_OWNED_CLAIM_ID,
SBUF(a), SBUF(b),
0,0
)));
ASSERT(INVALID_ARGUMENT == (e=util_keylet(buf, 34, KEYLET_XCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID,
SBUF(a), SBUF(b),
0,0
)));
ASSERT(INVALID_ARGUMENT == (e=util_keylet(buf, 34, KEYLET_DID,
SBUF(a),
0,0,
0,0
)));
ASSERT(34 == (e=util_keylet(buf, 34, KEYLET_ORACLE,
SBUF(a), 3,
0,
0,0
)));
ASSERT(INVALID_ARGUMENT == (e=util_keylet(buf, 34, KEYLET_MPTOKEN_ISSUANCE,
SBUF(a),
0,0,
0,0
)));
ASSERT(INVALID_ARGUMENT == (e=util_keylet(buf, 34, KEYLET_MPTOKEN,
SBUF(a),
0,0,
0,0
)));
ASSERT(INVALID_ARGUMENT == (e=util_keylet(buf, 34, KEYLET_CREDENTIAL,
SBUF(a), SBUF(b),
0,0
)));
ASSERT(INVALID_ARGUMENT == (e=util_keylet(buf, 34, KEYLET_PERMISSIONED_DOMAIN,
SBUF(a),
0,0,
0,0
)));
ASSERT(34 == (e=util_keylet(buf, 34, KEYLET_CRON, SBUF(a), 1, 0, 0, 0)));
{

File diff suppressed because it is too large Load Diff

View File

@@ -355,7 +355,14 @@ HookAPI::sto_validate(Bytes const& data) const
{
int type = -1, field = -1, payload_start = -1, payload_length = -1;
auto const length = get_stobject_length(
upto, end, type, field, payload_start, payload_length, 0);
upto,
end,
type,
field,
payload_start,
payload_length,
hookCtx.applyCtx.view().rules(),
0);
if (!length)
return 0;
upto += length.value();
@@ -389,7 +396,14 @@ HookAPI::sto_subfield(Bytes const& data, uint32_t field_id) const
{
int type = -1, field = -1, payload_start = -1, payload_length = -1;
auto const length = get_stobject_length(
upto, end, type, field, payload_start, payload_length, 0);
upto,
end,
type,
field,
payload_start,
payload_length,
hookCtx.applyCtx.view().rules(),
0);
if (!length)
return Unexpected(PARSE_ERROR);
if ((type << 16) + field == field_id)
@@ -464,7 +478,14 @@ HookAPI::sto_subarray(Bytes const& data, uint32_t index_id) const
{
int type = -1, field = -1, payload_start = -1, payload_length = -1;
auto const length = get_stobject_length(
upto, end, type, field, payload_start, payload_length, 0);
upto,
end,
type,
field,
payload_start,
payload_length,
hookCtx.applyCtx.view().rules(),
0);
if (!length)
return Unexpected(PARSE_ERROR);
@@ -530,6 +551,7 @@ HookAPI::sto_emplace(
field,
payload_start,
payload_length,
hookCtx.applyCtx.view().rules(),
0);
if (!length)
return Unexpected(PARSE_ERROR);
@@ -565,7 +587,14 @@ HookAPI::sto_emplace(
{
int type = -1, field = -1, payload_start = -1, payload_length = -1;
auto const length = get_stobject_length(
upto, end, type, field, payload_start, payload_length, 0);
upto,
end,
type,
field,
payload_start,
payload_length,
hookCtx.applyCtx.view().rules(),
0);
if (!length)
return Unexpected(PARSE_ERROR);
if ((type << 16) + field == field_id)
@@ -2998,12 +3027,20 @@ HookAPI::get_stobject_length(
int& payload_start, // out - the start of actual payload data for this type
int& payload_length, // out - the length of actual payload data for this
// type
Rules const& rules,
int recursion_depth) // used internally
const
{
if (recursion_depth > 10)
return Unexpected(pe_excessive_nesting);
uint16_t max_sti_type = rules.enabled(featureHookAPISerializedType240)
? STI_CURRENCY
: STI_VECTOR256;
if (type > max_sti_type)
return pe_unknown_type_early;
unsigned char* end = maxptr;
unsigned char* upto = start;
int high = *upto >> 4;
@@ -3055,14 +3092,20 @@ HookAPI::get_stobject_length(
auto const& fieldObj = ripple::SField::getField;
*/
if (type < 1 || type > 19 || (type >= 9 && type <= 13))
// type 10~13 are reserved
if (type < 1 || max_sti_type < type || (10 <= type && type <= 13))
return Unexpected(pe_unknown_type_early);
// not supported types
if (type == STI_NUMBER || type == STI_UINT96 || type == STI_UINT192 ||
type == STI_UINT384 || type == STI_UINT512)
return pe_unknown_type_early;
bool is_vl =
(type == SerializedTypeID::STI_ACCOUNT ||
type == SerializedTypeID::STI_VL ||
type == SerializedTypeID::STI_PATHSET ||
type == SerializedTypeID::STI_VECTOR256);
(type == STI_ACCOUNT || type == STI_VL ||
(type == STI_PATHSET &&
!rules.enabled(featureHookAPISerializedType240)) ||
type == STI_VECTOR256);
int length = -1;
if (is_vl)
@@ -3095,42 +3138,116 @@ HookAPI::get_stobject_length(
return Unexpected(pe_unexpected_end);
}
}
else if ((type >= 1 && type <= 5) || type == 16 || type == 17)
else if (
(type >= STI_UINT16 && type <= STI_UINT256) || type == STI_UINT8 ||
type == STI_UINT160 || type == STI_CURRENCY)
{
switch (type)
{
case SerializedTypeID::STI_UINT16:
case STI_UINT16:
length = 2;
break;
case SerializedTypeID::STI_UINT32:
case STI_UINT32:
length = 4;
break;
case SerializedTypeID::STI_UINT64:
case STI_UINT64:
length = 8;
break;
case SerializedTypeID::STI_UINT128:
case STI_UINT128:
length = 16;
break;
case SerializedTypeID::STI_UINT256:
case STI_UINT256:
length = 32;
break;
case SerializedTypeID::STI_UINT8:
case STI_UINT8:
length = 1;
break;
case SerializedTypeID::STI_UINT160:
case STI_UINT160:
length = 20;
break;
case STI_CURRENCY:
length = 20;
break;
default:
length = -1;
break;
return -1;
}
}
else if (type == SerializedTypeID::STI_AMOUNT)
else if (type == STI_AMOUNT) /* AMOUNT */
{
length = (*upto >> 6 == 1) ? 8 : 48;
if (upto >= end)
return Unexpected(pe_unexpected_end);
}
else if (
type == STI_PATHSET && rules.enabled(featureHookAPISerializedType240))
{
length = 0;
while (upto + length < end)
{
// iterate Path step
while (*(upto + length) & 0x01 || *(upto + length) & 0x10 ||
*(upto + length) & 0x20)
{
int flag = *(upto + length++);
// flag shoud be 0x01 or 0x10 or 0x20 or those union
if (flag == 0 || flag & ~(0x01 | 0x10 | 0x20))
return pe_unexpected_end;
if (flag & 0x01) // account
length += 20;
if (flag & 0x10) // currency
length += 20;
if (flag & 0x20) // issuer
length += 20;
int next_flag = *(upto + length);
if (next_flag == 0x00 || next_flag == 0xff)
// end of Path step
break;
}
// continue or end of Paths
int lastflag = *(upto + length++);
if (lastflag == 0xff)
continue; // continue byte
else if (lastflag == 0x00)
break; // end byte
else
return pe_unexpected_end;
}
if (upto >= end)
return pe_unexpected_end;
}
else if (type == STI_ISSUE)
{
auto zero20 = std::array<char, 20>{0};
// if first 20 byte is all zeros return 20
// else return 40
if (memcmp(upto, zero20.data(), 20) == 0)
length = 20;
else
length = 40;
}
else if (type == STI_XCHAIN_BRIDGE)
{
auto zero20 = std::array<char, 20>{0};
// Lock Chain
length = 1; // Door Account1 prefix length
length += 20; // Door Account1 length
// Door Issue1
if (memcmp(upto + length, zero20.data(), 20) == 0)
length += 20; // only Currency
else
length += 40; // Currency and Issue
// Issuing Chain
length += 1; // Door Account2 prefix length
length += 20; // Door Account2 length
// Door Issue2
if (memcmp(upto + length, zero20.data(), 20) == 0)
length += 20; // only Currency
else
length += 40; // Currency and Issue
}
if (length > -1)
{
@@ -3149,8 +3266,7 @@ HookAPI::get_stobject_length(
return length + (upto - start);
}
if (type == SerializedTypeID::STI_OBJECT ||
type == SerializedTypeID::STI_ARRAY)
if (type == STI_OBJECT || type == STI_ARRAY)
{
payload_start = upto - start;
@@ -3165,6 +3281,7 @@ HookAPI::get_stobject_length(
subfield,
payload_start_,
payload_length_,
hookCtx.applyCtx.view().rules(),
recursion_depth + 1);
DBG_PRINTF(
"%d get_stobject_length i %d %d-%d, upto %d sublength %d\n",
@@ -3180,8 +3297,8 @@ HookAPI::get_stobject_length(
if (upto >= end)
return Unexpected(pe_unexpected_end);
if ((*upto == 0xE1U && type == 0xEU) ||
(*upto == 0xF1U && type == 0xFU))
if ((*upto == 0xE1U && type == 0xEU) || // STI_OBJECT Maker
(*upto == 0xF1U && type == 0xFU)) // STI_ARRAY Maker
{
payload_length = upto - start - payload_start;
upto++;

View File

@@ -2327,7 +2327,13 @@ DEFINE_HOOK_FUNCTION(
case keylet_code::OWNER_DIR:
case keylet_code::SIGNERS:
case keylet_code::ACCOUNT:
case keylet_code::HOOK: {
case keylet_code::HOOK:
case keylet_code::DID: {
if (keylet_type == keylet_code::DID)
{
if (!applyCtx.view().rules().enabled(featureDID))
return INVALID_ARGUMENT;
}
if (a == 0 || b == 0)
return INVALID_ARGUMENT;
@@ -2350,13 +2356,43 @@ DEFINE_HOOK_FUNCTION(
? ripple::keylet::signers(id)
: keylet_type == keylet_code::OWNER_DIR
? ripple::keylet::ownerDir(id)
: keylet_type == keylet_code::DID
? ripple::keylet::did(id)
: ripple::keylet::account(id);
return serialize_keylet(kl, memory, write_ptr, write_len);
}
// keylets that take 20 byte account id, and (4 byte uint for 32
// byte hash)
// keylets that take 20 byte account id, and (4 byte uint for 32
// byte hash)
case keylet_code::ORACLE: {
if (!applyCtx.view().rules().enabled(featurePriceOracle))
return INVALID_ARGUMENT;
if (a == 0 || b == 0)
return INVALID_ARGUMENT;
if (d != 0 || e != 0 || f != 0)
return INVALID_ARGUMENT;
uint32_t read_ptr = a, read_len = b;
if (NOT_IN_BOUNDS(read_ptr, read_len, memory_length))
return OUT_OF_BOUNDS;
if (read_len != 20)
return INVALID_ARGUMENT;
ripple::AccountID id = AccountID::fromVoid(memory + read_ptr);
uint32_t seqId = c;
ripple::Keylet kl = ripple::keylet::oracle(id, seqId);
return serialize_keylet(kl, memory, write_ptr, write_len);
}
// keylets that take 20 byte account id, and UInt32or256 (4 byte
// uint or 32 byte hash)
case keylet_code::OFFER:
case keylet_code::CHECK:
case keylet_code::ESCROW:
@@ -2639,6 +2675,62 @@ DEFINE_HOOK_FUNCTION(
return serialize_keylet(kl, memory, write_ptr, write_len);
}
// keylets that take two 40 byte assets
case keylet_code::AMM: {
if (!applyCtx.view().rules().enabled(featureAMM))
return INVALID_ARGUMENT;
if (a == 0 || b == 0 || c == 0 || d == 0)
return INVALID_ARGUMENT;
if (e != 0 || f != 0)
return INVALID_ARGUMENT;
uint32_t aread_ptr = a, aread_len = b;
uint32_t bread_ptr = c, bread_len = d;
if (NOT_IN_BOUNDS(aread_ptr, aread_len, memory_length) ||
NOT_IN_BOUNDS(bread_ptr, bread_len, memory_length))
return OUT_OF_BOUNDS;
if (aread_len != 40 || bread_len != 40)
return INVALID_ARGUMENT;
Currency aCur = Currency::fromVoid(memory + aread_ptr);
Currency bCur = Currency::fromVoid(memory + bread_ptr);
AccountID aAcc = AccountID::fromVoid(memory + aread_ptr + 20);
AccountID bAcc = AccountID::fromVoid(memory + bread_ptr + 20);
Issue aIss = Issue{aCur, aAcc};
Issue bIss = Issue{bCur, bAcc};
ripple::Keylet kl =
ripple::keylet::amm(Asset{aIss}, Asset{bIss});
return serialize_keylet(kl, memory, write_ptr, write_len);
}
case keylet_code::BRIDGE:
case keylet_code::XCHAIN_OWNED_CLAIM_ID:
case keylet_code::XCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID: {
if (!applyCtx.view().rules().enabled(featureXChainBridge))
return INVALID_ARGUMENT;
}
case keylet_code::MPTOKEN_ISSUANCE:
case keylet_code::MPTOKEN: {
if (!applyCtx.view().rules().enabled(featureMPTokensV1))
return INVALID_ARGUMENT;
}
case keylet_code::CREDENTIAL: {
if (!applyCtx.view().rules().enabled(featureCredentials))
return INVALID_ARGUMENT;
}
case keylet_code::PERMISSIONED_DOMAIN: {
if (!applyCtx.view().rules().enabled(
featurePermissionedDomains))
return INVALID_ARGUMENT;
}
}
}
catch (std::exception& e)