mirror of
https://github.com/Xahau/xahaud.git
synced 2026-02-18 04:42:23 +00:00
Compare commits
3 Commits
sync-2.4.0
...
sync-2.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ecfbfc8ff | ||
|
|
3c49f80013 | ||
|
|
090e4ad25e |
24
.github/workflows/guard-checker-build.yml
vendored
Normal file
24
.github/workflows/guard-checker-build.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
name: Guard Checker Build
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
guard-checker-build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- run-on: ubuntu-latest
|
||||
- run-on: macos-latest
|
||||
runs-on: ${{ matrix.run-on }}
|
||||
name: Guard Checker Build - ${{ matrix.run-on }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Build Guard Checker
|
||||
run: |
|
||||
cd include/xrpl/hook
|
||||
make guard_checker
|
||||
@@ -140,6 +140,7 @@ test.toplevel > test.csf
|
||||
test.toplevel > xrpl.json
|
||||
test.unit_test > xrpl.basics
|
||||
xrpl.hook > xrpl.basics
|
||||
xrpl.hook > xrpl.protocol
|
||||
xrpl.json > xrpl.basics
|
||||
xrpl.protocol > xrpl.basics
|
||||
xrpl.protocol > xrpl.json
|
||||
|
||||
@@ -60,7 +60,7 @@ git-subtree. See those directories' README files for more details.
|
||||
- [Xrpl Documentation](https://xrpl.org)
|
||||
- [Xahau Documentation](https://xahau.network/)
|
||||
- [Hooks Technical Documentation](https://xrpl-hooks.readme.io/)
|
||||
- **Explorers**: Explore the Xahau ledger using various explorers:
|
||||
- **Explorers**: Explore the Xahau Network using various explorers:
|
||||
- [xahauexplorer.com](https://xahauexplorer.com)
|
||||
- [xahscan.com](https://xahscan.com)
|
||||
- [xahau.xrpl.org](https://xahau.xrpl.org)
|
||||
|
||||
@@ -62,11 +62,11 @@ For these complaints or reports, please [contact our support team](mailto:bugs@x
|
||||
### The following type of security problems are excluded
|
||||
|
||||
1. **In scope**. Only bugs in software under the scope of the program qualify. Currently, that means `xahaud` and `xahau-lib`.
|
||||
2. **Relevant**. A security issue, posing a danger to user funds, privacy or the operation of the Xahau Ledger.
|
||||
2. **Relevant**. A security issue, posing a danger to user funds, privacy or the operation of the Xahau Network.
|
||||
3. **Original and previously unknown**. Bugs that are already known and discussed in public do not qualify. Previously reported bugs, even if publicly unknown, are not eligible.
|
||||
4. **Specific**. We welcome general security advice or recommendations, but we cannot pay bounties for that.
|
||||
5. **Fixable**. There has to be something we can do to permanently fix the problem. Note that bugs in other people’s software may still qualify in some cases. For example, if you find a bug in a library that we use which can compromise the security of software that is in scope and we can get it fixed, you may qualify for a bounty.
|
||||
6. **Unused**. If you use the exploit to attack the Xahau Ledger, you do not qualify for a bounty. If you report a vulnerability used in an ongoing or past attack and there is specific, concrete evidence that suggests you are the attacker we reserve the right not to pay a bounty.
|
||||
6. **Unused**. If you use the exploit to attack the Xahau Network, you do not qualify for a bounty. If you report a vulnerability used in an ongoing or past attack and there is specific, concrete evidence that suggests you are the attacker we reserve the right not to pay a bounty.
|
||||
|
||||
Please note: Reports that are lacking any proof (such as screenshots or other data), detailed information or details on how to reproduce any unexpected result will be investigated but will not be eligible for any reward.
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
#define HOOKENUM_INCLUDED 1
|
||||
|
||||
#ifndef GUARD_CHECKER_BUILD
|
||||
#include <ripple/basics/base_uint.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/Rules.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Rules.h>
|
||||
#else
|
||||
// Override uint256, Feature and Rules for guard checker build
|
||||
#define uint256 std::string
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ public:
|
||||
STTx const emitInvokeTx = STTx(ttINVOKE, [&](STObject& obj) {
|
||||
obj[sfAccount] = alice.id();
|
||||
obj[sfSequence] = 0;
|
||||
obj[sfSigningPubKey] = PublicKey();
|
||||
obj[sfSigningPubKey] = Slice{};
|
||||
obj[sfFirstLedgerSequence] = env.closed()->seq() + 1;
|
||||
obj[sfLastLedgerSequence] = env.closed()->seq() + 5;
|
||||
obj[sfFee] = env.closed()->fees().base;
|
||||
@@ -110,7 +110,7 @@ public:
|
||||
STTx const emitSetHookTx = STTx(ttHOOK_SET, [&](STObject& obj) {
|
||||
obj[sfAccount] = alice.id();
|
||||
obj[sfSequence] = 0;
|
||||
obj[sfSigningPubKey] = PublicKey();
|
||||
obj[sfSigningPubKey] = Slice{};
|
||||
obj[sfFirstLedgerSequence] = env.closed()->seq() + 1;
|
||||
obj[sfLastLedgerSequence] = env.closed()->seq() + 5;
|
||||
obj[sfFee] = env.closed()->fees().base;
|
||||
|
||||
@@ -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
@@ -70,7 +70,7 @@ namespace hook_api {
|
||||
DECLARE_HOOK_FUNCTION( \
|
||||
RETURN_TYPE, FUNCTION_NAME, HOOK_WRAP_PARAMS PARAMS_TUPLE);
|
||||
|
||||
#include <ripple/app/hook/hook_api.macro>
|
||||
#include <xrpl/hook/hook_api.macro>
|
||||
|
||||
#undef HOOK_API_DEFINITION
|
||||
#undef HOOK_WRAP_PARAMS
|
||||
@@ -468,7 +468,7 @@ public:
|
||||
#define HOOK_API_DEFINITION(RETURN_TYPE, FUNCTION_NAME, PARAMS_TUPLE, ...) \
|
||||
ADD_HOOK_FUNCTION(FUNCTION_NAME, ctx);
|
||||
|
||||
#include <ripple/app/hook/hook_api.macro>
|
||||
#include <xrpl/hook/hook_api.macro>
|
||||
|
||||
#undef HOOK_API_DEFINITION
|
||||
#undef HOOK_WRAP_PARAMS
|
||||
|
||||
@@ -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++;
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user