Compare commits

..

22 Commits

Author SHA1 Message Date
Richard Holland
f4ff7bd4de Merge branch 'dev' into fixImportIssuer 2026-04-29 10:43:25 +10:00
tequ
b79fde27f1 Merge branch 'dev' into fixImportIssuer 2026-04-29 08:53:20 +09:00
tequ
46fb152b12 Merge branch 'dev' into fixImportIssuer 2026-04-28 20:52:54 +09:00
tequ
ce0ae8294e Merge branch 'dev' into fixImportIssuer 2026-04-24 14:09:48 +09:00
Alloy Networks
cd00ed72d8 change build instructions url 2026-04-24 11:12:28 +10:00
tequ
05a3e04f2d Fix BEAST_ENHANCED_LOGGING not working and restore original behavior 2026-04-24 11:11:40 +10:00
tequ
66f7294120 Test: hint build_test_hooks.sh when hook wasm is empty in hso() 2026-04-24 11:10:46 +10:00
Nicholas Dudfield
7f6ac75617 Revert "chore: use improved levelization script with threading and argparse"
This reverts commit 5c1d7d9ae9.
2026-04-24 11:09:19 +10:00
Nicholas Dudfield
4150f0383c chore: use improved levelization script with threading and argparse 2026-04-24 11:09:19 +10:00
Nicholas Dudfield
25123b370a chore: replace levelization shell script with python
Backport of XRPLF/rippled#6325. The python version runs ~80x faster.
2026-04-24 11:09:19 +10:00
tequ
f90ed41802 enable ccache direct_mode 2026-04-24 11:06:51 +10:00
tequ
8c4c158d3a output ccache configuration in release-builder 2026-04-24 11:06:51 +10:00
tequ
2d2951875d fix: typo SignersListSet 2026-04-24 11:05:20 +10:00
tequ
9bfca63574 Update util_keylet fee test 2026-04-24 11:00:31 +10:00
tequ
1ba444ae7f Updated tests to align with the changes merged into the dev branch. 2026-04-24 11:00:31 +10:00
tequ
f96d9b6e51 Add tests for Hooks fee 2026-04-24 11:00:31 +10:00
tequ
9f33cad6db Disallow setting a AMM account as Issuer/Destination/Inform 2026-03-10 15:35:18 +09:00
tequ
8cfee6c8a3 Merge fixAMMClawbackRounding amendment into featureAMMClawback amendment 2026-02-25 19:07:45 +10:00
yinyiqian1
8673599d2b fixAMMClawbackRounding: adjust last holder's LPToken balance (#5513)
Due to rounding, the LPTokenBalance of the last LP might not match the LP's trustline balance. This was fixed for `AMMWithdraw` in `fixAMMv1_1` by adjusting the LPTokenBalance to be the same as the trustline balance. Since `AMMClawback` is also performing a withdrawal, we need to adjust LPTokenBalance as well in `AMMClawback.`

This change includes:
1. Refactored `verifyAndAdjustLPTokenBalance` function in `AMMUtils`, which both`AMMWithdraw` and `AMMClawback` call to adjust LPTokenBalance.
2. Added the unit test `testLastHolderLPTokenBalance` to test the scenario.
3. Modify the existing unit tests for `fixAMMClawbackRounding`.
2026-02-25 19:07:45 +10:00
tequ
ec65e622aa Merge fixAMMv1_3 amendment into featureAMM amendment 2026-02-25 16:20:43 +10:00
Gregory Tsipenyuk
65837f49e1 fix: Add AMMv1_3 amendment (#5203)
* Add AMM bid/create/deposit/swap/withdraw/vote invariants:
  - Deposit, Withdrawal invariants: `sqrt(asset1Balance * asset2Balance) >= LPTokens`.
  - Bid: `sqrt(asset1Balance * asset2Balance) > LPTokens` and the pool balances don't change.
  - Create: `sqrt(asset1Balance * assetBalance2) == LPTokens`.
  - Swap: `asset1BalanceAfter * asset2BalanceAfter >= asset1BalanceBefore * asset2BalanceBefore`
     and `LPTokens` don't change.
  - Vote: `LPTokens` and pool balances don't change.
  - All AMM and swap transactions: amounts and tokens are greater than zero, except on withdrawal if all tokens
    are withdrawn.
* Add AMM deposit and withdraw rounding to ensure AMM invariant:
  - On deposit, tokens out are rounded downward and deposit amount is rounded upward.
  - On withdrawal, tokens in are rounded upward and withdrawal amount is rounded downward.
* Add Order Book Offer invariant to verify consumed amounts. Consumed amounts are less than the offer.
* Fix Bid validation. `AuthAccount` can't have duplicate accounts or the submitter account.
2026-02-25 16:20:43 +10:00
RichardAH
e5b21f026e Merge pull request #692 from Xahau/sync-2.4.0-rebased
Sync: Ripple(d) 2.4.0
2026-02-24 16:07:09 +10:00
38 changed files with 1522 additions and 649 deletions

View File

@@ -20,7 +20,7 @@ jobs:
sudo apt-get update
sudo apt-get install clang-format-${CLANG_VERSION}
- name: Format first-party sources
run: find include src -type f \( -name '*.cpp' -o -name '*.hpp' -o -name '*.h' -o -name '*.ipp' \) -exec clang-format-${CLANG_VERSION} -i {} +
run: find include src -type f \( -name '*.cpp' -o -name '*.hpp' -o -name '*.h' -o -name '*.ipp' \) -not -path "src/magic/magic_enum.h" -exec clang-format-${CLANG_VERSION} -i {} +
- name: Check for differences
id: assert
run: |

View File

@@ -18,10 +18,6 @@ jobs:
generator: bash ./hook/generate_sfcodes.sh
- target: hook/tts.h
generator: ./hook/generate_tts.sh
- target: hook/ls_flags.h
generator: ./hook/generate_lsflags.sh
- target: hook/tx_flags.h
generator: ./hook/generate_txflags.sh
runs-on: ubuntu-24.04
env:
CLANG_VERSION: 18

View File

@@ -122,7 +122,6 @@ endif()
find_package(nudb REQUIRED)
find_package(date REQUIRED)
find_package(xxHash REQUIRED)
find_package(magic_enum REQUIRED)
include(deps/WasmEdge)
if(TARGET nudb::core)

View File

@@ -380,7 +380,6 @@ function(setup_target_for_coverage_gcovr)
${GCOVR_PATH}
--gcov-executable ${GCOV_TOOL}
--gcov-ignore-parse-errors=negative_hits.warn_once_per_file
--gcov-ignore-parse-errors=suspicious_hits.warn_once_per_file
-r ${BASEDIR}
${GCOVR_ADDITIONAL_ARGS}
${GCOVR_EXCLUDE_ARGS}

View File

@@ -54,7 +54,6 @@ add_library(xrpl.imports.main INTERFACE)
target_link_libraries(xrpl.imports.main
INTERFACE
LibArchive::LibArchive
magic_enum::magic_enum
OpenSSL::Crypto
Ripple::boost
wasmedge::wasmedge

View File

@@ -29,7 +29,6 @@ class Xrpl(ConanFile):
'date/3.0.3',
'grpc/1.50.1',
'libarchive/3.7.6',
'magic_enum/0.9.5',
'nudb/2.0.8',
'openssl/3.6.0',
'soci/4.0.3@xahaud/stable',

View File

@@ -1,82 +0,0 @@
#!/bin/bash
set -eu
SCRIPT_DIR=$(dirname "$0")
SCRIPT_DIR=$(cd "$SCRIPT_DIR" && pwd)
RIPPLED_ROOT="$SCRIPT_DIR/../include/xrpl"
LEDGER_FORMATS="$RIPPLED_ROOT/protocol/LedgerFormats.h"
echo '// Generated using generate_lsflags.sh'
echo ''
echo '#ifndef HOOKLSFLAGS_INCLUDED'
echo '#define HOOKLSFLAGS_INCLUDED 1'
echo ''
awk '
function ltrim(s) { sub(/^[[:space:]]+/, "", s); return s }
function rtrim(s) { sub(/[[:space:]]+$/, "", s); return s }
function trim(s) { return rtrim(ltrim(s)) }
function flush_group() {
if (entry_count > 0 && group != "") {
printf "enum %s {\n", group
for (i = 1; i <= entry_count; i++) {
printf " %s,\n", entries[i]
}
printf "};\n"
}
delete entries
entry_count = 0
}
/enum LedgerSpecificFlags \{/ { inside = 1; next }
inside && /^\};/ { inside = 0; flush_group(); next }
!inside { next }
# Group header comments: // ltFOO or // remarks
/^[[:space:]]*\/\/[[:space:]]*(lt[A-Z_]+|remarks)[[:space:]]*$/ {
flush_group()
line = $0
sub(/.*\/\/[[:space:]]*/, "", line)
group = trim(line)
next
}
# Skip pure comment lines (not group headers)
/^[[:space:]]*\/\// { next }
# Skip blank lines
/^[[:space:]]*$/ { next }
# Accumulate flag lines (handle multi-line values)
{
line = $0
# Strip inline comments
sub(/\/\/.*/, "", line)
line = trim(line)
if (line == "") next
if (pending != "") {
pending = pending " " line
} else {
pending = line
}
# If line ends with comma, the entry is complete
if (pending ~ /,$/) {
# Remove trailing comma
sub(/,$/, "", pending)
entries[++entry_count] = pending
pending = ""
}
}
BEGIN {
inside = 0
group = ""
pending = ""
entry_count = 0
}
' "$LEDGER_FORMATS"
echo ''
echo '#endif // HOOKLSFLAGS_INCLUDED'

View File

@@ -1,25 +0,0 @@
#!/bin/bash
set -eu
SCRIPT_DIR=$(dirname "$0")
SCRIPT_DIR=$(cd "$SCRIPT_DIR" && pwd)
RIPPLED_ROOT="$SCRIPT_DIR/../include/xrpl"
TX_FLAGS="$RIPPLED_ROOT/protocol/TxFlags.h"
echo '// Generated using generate_txflags.sh'
echo '#include "ls_flags.h"'
echo '#include <stdint.h>'
echo ''
cat "$TX_FLAGS" |
awk '
/^[[:space:]]*enum / {
if (count > 0) print ""
inside = 1
count++
}
inside {
print
if (/};/) inside = 0
}
'

View File

@@ -49,7 +49,4 @@
#include "macro.h"
#include "tts.h"
#include "ls_flags.h"
#include "tx_flags.h"
#endif

View File

@@ -1,75 +0,0 @@
// Generated using generate_lsflags.sh
#ifndef HOOKLSFLAGS_INCLUDED
#define HOOKLSFLAGS_INCLUDED 1
enum ltACCOUNT_ROOT {
lsfPasswordSpent = 0x00010000,
lsfRequireDestTag = 0x00020000,
lsfRequireAuth = 0x00040000,
lsfDisallowXRP = 0x00080000,
lsfDisableMaster = 0x00100000,
lsfNoFreeze = 0x00200000,
lsfGlobalFreeze = 0x00400000,
lsfDefaultRipple = 0x00800000,
lsfDepositAuth = 0x01000000,
lsfTshCollect = 0x02000000,
lsfDisallowIncomingNFTokenOffer = 0x04000000,
lsfDisallowIncomingCheck = 0x08000000,
lsfDisallowIncomingPayChan = 0x10000000,
lsfDisallowIncomingTrustline = 0x20000000,
lsfURITokenIssuer = 0x40000000,
lsfDisallowIncomingRemit = 0x80000000,
lsfAllowTrustLineClawback = 0x00001000,
};
enum ltOFFER {
lsfPassive = 0x00010000,
lsfSell = 0x00020000,
};
enum ltRIPPLE_STATE {
lsfLowReserve = 0x00010000,
lsfHighReserve = 0x00020000,
lsfLowAuth = 0x00040000,
lsfHighAuth = 0x00080000,
lsfLowNoRipple = 0x00100000,
lsfHighNoRipple = 0x00200000,
lsfLowFreeze = 0x00400000,
lsfHighFreeze = 0x00800000,
lsfLowDeepFreeze = 0x02000000,
lsfHighDeepFreeze = 0x04000000,
lsfAMMNode = 0x01000000,
};
enum ltSIGNER_LIST {
lsfOneOwnerCount = 0x00010000,
};
enum ltDIR_NODE {
lsfNFTokenBuyOffers = 0x00000001,
lsfNFTokenSellOffers = 0x00000002,
lsfEmittedDir = 0x00000004,
};
enum ltNFTOKEN_OFFER {
lsfSellNFToken = 0x00000001,
};
enum ltURI_TOKEN {
lsfBurnable = 0x00000001,
};
enum remarks {
lsfImmutable = 1,
};
enum ltMPTOKEN_ISSUANCE {
lsfMPTLocked = 0x00000001,
lsfMPTCanLock = 0x00000002,
lsfMPTRequireAuth = 0x00000004,
lsfMPTCanEscrow = 0x00000008,
lsfMPTCanTrade = 0x00000010,
lsfMPTCanTransfer = 0x00000020,
lsfMPTCanClawback = 0x00000040,
};
enum ltMPTOKEN {
lsfMPTAuthorized = 0x00000002,
};
enum ltCREDENTIAL {
lsfAccepted = 0x00010000,
};
#endif // HOOKLSFLAGS_INCLUDED

View File

@@ -274,6 +274,7 @@
#define sfDisabledValidator ((14U << 16U) + 19U)
#define sfEmittedTxn ((14U << 16U) + 20U)
#define sfHookExecution ((14U << 16U) + 21U)
#define sfHookDefinition ((14U << 16U) + 22U)
#define sfHookParameter ((14U << 16U) + 23U)
#define sfHookGrant ((14U << 16U) + 24U)
#define sfVoteEntry ((14U << 16U) + 25U)

View File

@@ -1,117 +0,0 @@
// Generated using generate_txflags.sh
#include "ls_flags.h"
#include <stdint.h>
enum UniversalFlags : uint32_t {
tfFullyCanonicalSig = 0x80000000,
};
enum AccountSetFlags : uint32_t {
tfRequireDestTag = 0x00010000,
tfOptionalDestTag = 0x00020000,
tfRequireAuth = 0x00040000,
tfOptionalAuth = 0x00080000,
tfDisallowXRP = 0x00100000,
tfAllowXRP = 0x00200000,
};
enum AccountFlags : uint32_t {
asfRequireDest = 1,
asfRequireAuth = 2,
asfDisallowXRP = 3,
asfDisableMaster = 4,
asfAccountTxnID = 5,
asfNoFreeze = 6,
asfGlobalFreeze = 7,
asfDefaultRipple = 8,
asfDepositAuth = 9,
asfAuthorizedNFTokenMinter = 10,
asfTshCollect = 11,
asfDisallowIncomingNFTokenOffer = 12,
asfDisallowIncomingCheck = 13,
asfDisallowIncomingPayChan = 14,
asfDisallowIncomingTrustline = 15,
asfDisallowIncomingRemit = 16,
asfAllowTrustLineClawback = 17,
};
enum OfferCreateFlags : uint32_t {
tfPassive = 0x00010000,
tfImmediateOrCancel = 0x00020000,
tfFillOrKill = 0x00040000,
tfSell = 0x00080000,
};
enum PaymentFlags : uint32_t {
tfNoRippleDirect = 0x00010000,
tfPartialPayment = 0x00020000,
tfLimitQuality = 0x00040000,
};
enum TrustSetFlags : uint32_t {
tfSetfAuth = 0x00010000,
tfSetNoRipple = 0x00020000,
tfClearNoRipple = 0x00040000,
tfSetFreeze = 0x00100000,
tfClearFreeze = 0x00200000,
tfSetDeepFreeze = 0x00400000,
tfClearDeepFreeze = 0x00800000
};
enum EnableAmendmentFlags : uint32_t {
tfGotMajority = 0x00010000,
tfLostMajority = 0x00020000,
tfTestSuite = 0x80000000,
};
enum PaymentChannelClaimFlags : uint32_t {
tfRenew = 0x00010000,
tfClose = 0x00020000,
};
enum NFTokenMintFlags : uint32_t {
tfBurnable = 0x00000001,
tfOnlyXRP = 0x00000002,
tfTrustLine = 0x00000004,
tfTransferable = 0x00000008,
tfMutable = 0x00000010,
tfStrongTSH = 0x00008000,
};
enum MPTokenIssuanceCreateFlags : uint32_t {
tfMPTCanLock = lsfMPTCanLock,
tfMPTRequireAuth = lsfMPTRequireAuth,
tfMPTCanEscrow = lsfMPTCanEscrow,
tfMPTCanTrade = lsfMPTCanTrade,
tfMPTCanTransfer = lsfMPTCanTransfer,
tfMPTCanClawback = lsfMPTCanClawback,
};
enum MPTokenAuthorizeFlags : uint32_t {
tfMPTUnauthorize = 0x00000001,
};
enum MPTokenIssuanceSetFlags : uint32_t {
tfMPTLock = 0x00000001,
tfMPTUnlock = 0x00000002,
};
enum NFTokenCreateOfferFlags : uint32_t {
tfSellNFToken = 0x00000001,
};
enum ClaimRewardFlags : uint32_t {
tfOptOut = 0x00000001,
};
enum CronSetFlags : uint32_t {
tfCronUnset = 0x00000001,
};
enum AMMClawbackFlags : uint32_t {
tfClawTwoAssets = 0x00000001,
};
enum BridgeModifyFlags : uint32_t {
tfClearAccountCreateAmount = 0x00010000,
};

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 = 115;
static constexpr std::size_t numFeatures = 114;
/** Amendments that this server supports and the default voting behavior.
Whether they are enabled depends on the Rules defined in the validated

View File

@@ -132,7 +132,7 @@ constexpr std::uint32_t tfTrustSetMask =
tfClearFreeze | tfSetDeepFreeze | tfClearDeepFreeze);
// EnableAmendment flags:
enum EnableAmendmentFlags : uint32_t {
enum EnableAmendmentFlags : std::uint32_t {
tfGotMajority = 0x00010000,
tfLostMajority = 0x00020000,
tfTestSuite = 0x80000000,

View File

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

View File

@@ -367,7 +367,7 @@ UNTYPED_SFIELD(sfMajority, OBJECT, 18)
UNTYPED_SFIELD(sfDisabledValidator, OBJECT, 19)
UNTYPED_SFIELD(sfEmittedTxn, OBJECT, 20)
UNTYPED_SFIELD(sfHookExecution, OBJECT, 21)
// 22 unused
UNTYPED_SFIELD(sfHookDefinition, OBJECT, 22)
UNTYPED_SFIELD(sfHookParameter, OBJECT, 23)
UNTYPED_SFIELD(sfHookGrant, OBJECT, 24)
UNTYPED_SFIELD(sfVoteEntry, OBJECT, 25)

View File

@@ -31,8 +31,6 @@
namespace ripple {
#define LEDGER_NAMESPACE2(value1, value2) (uint16_t(value1) << 8) | value2
/** Type-specific prefix for calculating ledger indices.
The identifier for a given object within the ledger is calculated based
@@ -82,14 +80,14 @@ enum class LedgerNameSpace : std::uint16_t {
UNL_REPORT = 'R',
CRON = 'L',
AMM = 'A',
BRIDGE = LEDGER_NAMESPACE2(0x01, 'H'),
BRIDGE = 'H',
XCHAIN_CLAIM_ID = 'Q',
XCHAIN_CREATE_ACCOUNT_CLAIM_ID = 'K',
DID = LEDGER_NAMESPACE2(0x01, 'I'),
ORACLE = LEDGER_NAMESPACE2(0x01, 'R'),
DID = 'I',
ORACLE = 'R',
MPTOKEN_ISSUANCE = '~',
MPTOKEN = 't',
CREDENTIAL = LEDGER_NAMESPACE2(0x01, 'D'),
CREDENTIAL = 'D',
PERMISSIONED_DOMAIN = 'm',
// No longer used or supported. Left here to reserve the space

View File

@@ -87,6 +87,19 @@ InnerObjectFormats::InnerObjectFormats()
{sfEmittedTxnID, soeREQUIRED},
{sfEmitNonce, soeOPTIONAL}});
add(sfHookDefinition.jsonName,
sfHookDefinition.getCode(),
{{sfCreateCode, soeREQUIRED},
{sfHookNamespace, soeREQUIRED},
{sfHookParameters, soeREQUIRED},
{sfHookOn, soeOPTIONAL},
{sfHookOnIncoming, soeOPTIONAL},
{sfHookOnOutgoing, soeOPTIONAL},
{sfHookCanEmit, soeOPTIONAL},
{sfHookApiVersion, soeREQUIRED},
{sfFlags, soeREQUIRED},
{sfFee, soeREQUIRED}});
add(sfHook.jsonName,
sfHook.getCode(),
{{sfHookHash, soeOPTIONAL},

1474
src/magic/magic_enum.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -20,8 +20,6 @@
#include <test/jtx.h>
#include <test/jtx/envconfig.h>
#include <xrpld/app/paths/AccountCurrencies.h>
#include <xrpld/app/paths/Pathfinder.h>
#include <xrpld/app/paths/RippleLineCache.h>
#include <xrpld/core/JobQueue.h>
#include <xrpld/rpc/Context.h>
#include <xrpld/rpc/RPCHandler.h>
@@ -575,164 +573,6 @@ public:
BEAST_EXPECT(equal(sa, Account("alice")["USD"](5)));
}
Json::Value
six_path_append_request_result()
{
using namespace jtx;
Env env = pathTestEnv();
Account A1{"A1"};
Account A2{"A2"};
Account G1{"G1"};
Account G2{"G2"};
Account M1{"M1"};
Account M2{"M2"};
Account M3{"M3"};
Account M4{"M4"};
Account M5{"M5"};
Account M6{"M6"};
Account MM{"MM"};
env.fund(XRP(1000), A1, A2, G1, G2, M1, M2, M3, M4, M5, M6, MM);
env.close();
env.trust(G1["HKD"](2000), A1);
env.trust(G2["HKD"](2000), A2);
env.trust(G1["HKD"](100000), M1, M2, M3, M4, M5, M6, MM);
env.trust(G2["HKD"](100000), M1, M2, M3, M4, M5, M6, MM);
env.close();
env(pay(G1, A1, G1["HKD"](1000)));
env(pay(G1, M1, G1["HKD"](10)));
env(pay(G1, M2, G1["HKD"](10)));
env(pay(G1, M3, G1["HKD"](10)));
env(pay(G1, M4, G1["HKD"](10)));
env(pay(G1, M5, G1["HKD"](10)));
env(pay(G1, M6, G1["HKD"](10)));
env(pay(G1, MM, G1["HKD"](1000)));
env(pay(G2, M1, G2["HKD"](10)));
env(pay(G2, M2, G2["HKD"](10)));
env(pay(G2, M3, G2["HKD"](10)));
env(pay(G2, M4, G2["HKD"](10)));
env(pay(G2, M5, G2["HKD"](10)));
env(pay(G2, M6, G2["HKD"](10)));
env(pay(G2, MM, G2["HKD"](1000)));
env.close();
env(offer(MM, G1["HKD"](1000), G2["HKD"](100)));
env.close();
return find_paths_request(
env, A1, A2, A2["HKD"](60), std::nullopt, G1["HKD"].currency);
}
void
pathfind_paths_computed_never_exceeds_six()
{
testcase("pathfind paths_computed never exceeds six");
auto const result = six_path_append_request_result();
BEAST_EXPECT(result.isMember(jss::alternatives));
if (!result.isMember(jss::alternatives))
return;
BEAST_EXPECT(result[jss::alternatives].isArray());
if (!result[jss::alternatives].isArray())
return;
bool sawPathsComputed = false;
for (auto const& alt : result[jss::alternatives])
{
if (!alt.isMember(jss::paths_computed))
continue;
sawPathsComputed = true;
BEAST_EXPECT(alt[jss::paths_computed].isArray());
if (alt[jss::paths_computed].isArray())
BEAST_EXPECT(alt[jss::paths_computed].size() <= 6);
}
BEAST_EXPECT(sawPathsComputed);
}
void
pathfind_can_return_six_paths_with_append()
{
testcase("pathfind can return six paths with append");
using namespace jtx;
Env env = pathTestEnv();
Account A1{"A1"};
Account A2{"A2"};
Account G1{"G1"};
Account G2{"G2"};
Account M1{"M1"};
Account M2{"M2"};
Account M3{"M3"};
Account M4{"M4"};
Account M5{"M5"};
Account M6{"M6"};
Account MM{"MM"};
env.fund(XRP(1000), A1, A2, G1, G2, M1, M2, M3, M4, M5, M6, MM);
env.close();
env.trust(G1["HKD"](2000), A1);
env.trust(G2["HKD"](2000), A2);
env.trust(G1["HKD"](100000), M1, M2, M3, M4, M5, M6, MM);
env.trust(G2["HKD"](100000), M1, M2, M3, M4, M5, M6, MM);
env.close();
env(pay(G1, A1, G1["HKD"](1000)));
env(pay(G1, M1, G1["HKD"](10)));
env(pay(G1, M2, G1["HKD"](10)));
env(pay(G1, M3, G1["HKD"](10)));
env(pay(G1, M4, G1["HKD"](10)));
env(pay(G1, M5, G1["HKD"](10)));
env(pay(G1, M6, G1["HKD"](10)));
env(pay(G1, MM, G1["HKD"](1000)));
env(pay(G2, M1, G2["HKD"](10)));
env(pay(G2, M2, G2["HKD"](10)));
env(pay(G2, M3, G2["HKD"](10)));
env(pay(G2, M4, G2["HKD"](10)));
env(pay(G2, M5, G2["HKD"](10)));
env(pay(G2, M6, G2["HKD"](10)));
env(pay(G2, MM, G2["HKD"](1000)));
env.close();
env(offer(MM, G1["HKD"](1000), G2["HKD"](100)));
env.close();
auto cache = std::make_shared<RippleLineCache>(
env.current(), env.app().journal("RippleLineCache"));
Pathfinder pf(
cache,
A1.id(),
A2.id(),
G1["HKD"].currency,
std::nullopt,
A2["HKD"](60),
std::nullopt,
env.app());
BEAST_EXPECT(pf.findPaths(7));
pf.computePathRanks(5);
STPath fullLiquidityPath;
auto bestPaths =
pf.getBestPaths(5, fullLiquidityPath, STPathSet{}, A1.id());
BEAST_EXPECT(bestPaths.size() == 5);
BEAST_EXPECT(!fullLiquidityPath.empty());
if (!fullLiquidityPath.empty())
bestPaths.push_back(fullLiquidityPath);
BEAST_EXPECT(bestPaths.size() == 6);
}
void
issues_path_negative_issue()
{
@@ -1541,8 +1381,6 @@ public:
path_find_04();
path_find_05();
path_find_06();
pathfind_paths_computed_never_exceeds_six();
pathfind_can_return_six_paths_with_append();
}
};

View File

@@ -2891,39 +2891,6 @@ struct Remit_test : public beast::unit_test::suite
}
}
void
testDestAMM(FeatureBitset features)
{
testcase("remit to AMM Account");
using namespace test::jtx;
using namespace std::literals;
auto const alice = Account("alice");
auto const gw = Account("gw");
auto const USD = gw["USD"];
Env env{*this, features};
env.fund(XRP(10'000'000), alice, gw);
env.close();
env.trust(USD(100'000), alice);
env.close();
env(pay(gw, alice, USD(100'000)));
env.close();
AMM ammAlice(env, alice, XRP(10'000), USD(10'000));
env(remit::remit(alice, ammAlice.ammAccount()),
remit::amts({USD(10'000)}),
ter(tecNO_PERMISSION));
env(remit::remit(alice, ammAlice.ammAccount()),
remit::amts({XRP(10'000)}),
ter(tecNO_PERMISSION));
env(remit::remit(gw, ammAlice.ammAccount()),
remit::amts({gw["EUR"](10'000)}),
ter(tecNO_PERMISSION));
}
void
testWithFeats(FeatureBitset features)
{
@@ -2945,7 +2912,6 @@ struct Remit_test : public beast::unit_test::suite
testRippling(features);
testURIToken(features);
testOptionals(features);
testDestAMM(features);
}
public:

View File

@@ -63,7 +63,7 @@ countTx(std::shared_ptr<SHAMap> const& txSet)
auto tx = std::make_shared<STTx
const>(SerialIter{sit.getSlice(sit.getVLDataLength())});
if (tx->getTxnType() == ttUNL_MODIFY)
if (tx->getFieldU16(sfTransactionType) == ttUNL_MODIFY)
counter++;
}
*/

View File

@@ -28,6 +28,7 @@
#include <xrpl/protocol/STLedgerEntry.h>
#include <boost/algorithm/string/predicate.hpp>
#include <regex>
namespace ripple {
@@ -136,9 +137,7 @@ class Invariants_test : public beast::unit_test::suite
if (sink.messages().str().find(m) == std::string::npos)
{
// uncomment if you want to log the invariant failure
// message
// log << sink.messages().str() << std::endl;
// log << " --> " << m << std::endl;
// message log << " --> " << m << std::endl;
fail();
}
}
@@ -1234,42 +1233,6 @@ class Invariants_test : public beast::unit_test::suite
{tecINVARIANT_FAILED, tecINVARIANT_FAILED});
}
void
testLockedBalance()
{
using namespace test::jtx;
testcase << "ValidLockedBalance";
doInvariantCheck(
{{"Invariant failed: IOU locked balance is greater than balance"}},
[&](Account const& A1, Account const& A2, ApplyContext& ac) {
IOU const USD{A2["USD"]};
auto const sle =
std::make_shared<SLE>(keylet::line(A1, A2, USD.currency));
sle->setFieldAmount(sfHighLimit, A1["USD"](100));
sle->setFieldAmount(sfLowLimit, A2["USD"](100));
sle->setFieldAmount(sfBalance, USD(100));
sle->setFieldAmount(sfLockedBalance, USD(101));
ac.view().insert(sle);
return true;
});
doInvariantCheck(
{{"Invariant failed: IOU locked balance is greater than balance"}},
[&](Account const& A1, Account const& A2, ApplyContext& ac) {
IOU const USD{A2["USD"]};
auto const sle =
std::make_shared<SLE>(keylet::line(A1, A2, USD.currency));
sle->setFieldAmount(sfHighLimit, A1["USD"](100));
sle->setFieldAmount(sfLowLimit, A2["USD"](100));
sle->setFieldAmount(sfBalance, USD(-100));
sle->setFieldAmount(sfLockedBalance, USD(-101));
ac.view().insert(sle);
return true;
});
}
public:
void
run() override
@@ -1288,7 +1251,6 @@ public:
testValidNewAccountRoot();
testNFTokenPageInvariants();
testPermissionedDomainInvariants();
testLockedBalance();
}
};

View File

@@ -69,6 +69,7 @@ class Hooks_test : public beast::unit_test::suite
sfHookAccount,
sfEmittedTxn,
sfHook,
sfHookDefinition,
sfHookParameter,
sfHookGrant,
sfEmitDetails,

View File

@@ -2655,7 +2655,7 @@ HookAPI::meta_slot(uint32_t slot_into) const
Expected<std::pair<uint32_t, uint32_t>, HookReturnCode>
HookAPI::xpop_slot(uint32_t slot_into_tx, uint32_t slot_into_meta) const
{
if (hookCtx.applyCtx.tx.getTxnType() != ttIMPORT)
if (hookCtx.applyCtx.tx.getFieldU16(sfTransactionType) != ttIMPORT)
return Unexpected(PREREQUISITE_NOT_MET);
if (slot_into_tx > hook_api::max_slots ||

View File

@@ -41,7 +41,7 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
if (!otxnAcc)
return {};
TxType const& tt = tx.getTxnType();
uint16_t tt = tx.getFieldU16(sfTransactionType);
std::map<AccountID, std::pair<int, bool>> tshEntries;

View File

@@ -170,7 +170,7 @@ private:
std::chrono::steady_clock::time_point quick_reply_;
std::chrono::steady_clock::time_point full_reply_;
static unsigned int const max_paths_ = 5;
static unsigned int const max_paths_ = 4;
};
} // namespace ripple

View File

@@ -1324,13 +1324,11 @@ Pathfinder::initPathTable()
fillPaths(
pt_nonXRP_to_XRP,
{{1, "sxd"}, // gateway buys XRP
{2, "saxd"}, // source -> gateway -> book(XRP) -> dest
{5, "sabxd"}, // source -> gateway -> book -> book(XRP) -> dest
{{1, "sxd"}, // gateway buys XRP
{2, "saxd"}, // source -> gateway -> book(XRP) -> dest
{6, "saaxd"},
{7, "sbxd"},
{8,
"sabbxd"}, // source -> gateway -> book -> book -> book(XRP) -> dest
{8, "sabxd"},
{9, "sabaxd"}});
// non-XRP to non-XRP (same currency)

View File

@@ -1132,7 +1132,7 @@ Import::doRegularKey(std::shared_ptr<SLE>& sle, STTx const& stpTrans)
JLOG(ctx_.journal.trace()) << "Import: doRegularKey acc: " << id;
if (stpTrans.getTxnType() != ttREGULAR_KEY_SET)
if (stpTrans.getFieldU16(sfTransactionType) != ttREGULAR_KEY_SET)
{
JLOG(ctx_.journal.warn())
<< "Import: doRegularKey called on non-regular key transaction.";

View File

@@ -402,7 +402,7 @@ NoZeroEscrow::finalize(
if (bad_ && rv.rules().enabled(featurePaychanAndEscrowForTokens) &&
txn.isFieldPresent(sfTransactionType))
{
TxType const& tt = txn.getTxnType();
uint16_t const tt = txn.getFieldU16(sfTransactionType);
if (tt == ttESCROW_CANCEL || tt == ttESCROW_FINISH)
return true;
@@ -1982,44 +1982,4 @@ ValidAMM::finalize(
return true;
}
void
ValidLockedBalance::visitEntry(
bool,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after)
{
if (after && after->getType() == ltRIPPLE_STATE &&
after->isFieldPresent(sfLockedBalance))
{
iouIOULockedBalanceAfter_ = (*after)[sfLockedBalance];
iouIOUBalanceAfter_ = (*after)[sfBalance];
}
}
bool
ValidLockedBalance::finalize(
STTx const& tx,
TER const result,
XRPAmount const,
ReadView const& view,
beast::Journal const& j)
{
if (!view.rules().enabled(fixIOULockedBalanceInvariant))
return true;
if (iouIOULockedBalanceAfter_)
{
if ((!iouIOULockedBalanceAfter_->negative() &&
*iouIOULockedBalanceAfter_ > *iouIOUBalanceAfter_) ||
(iouIOULockedBalanceAfter_->negative() &&
*iouIOULockedBalanceAfter_ < *iouIOUBalanceAfter_))
{
JLOG(j.fatal()) << "Invariant failed: IOU locked balance is "
"greater than balance";
return false;
}
}
return true;
}
} // namespace ripple

View File

@@ -680,30 +680,6 @@ private:
beast::Journal const&) const;
};
class ValidLockedBalance
{
std::optional<STAmount> iouIOULockedBalanceAfter_;
std::optional<STAmount> iouIOUBalanceAfter_;
public:
ValidLockedBalance()
{
}
void
visitEntry(
bool,
std::shared_ptr<SLE const> const&,
std::shared_ptr<SLE const> const&);
bool
finalize(
STTx const&,
TER const,
XRPAmount const,
ReadView const&,
beast::Journal const&);
};
// additional invariant checks can be declared above and then added to this
// tuple
using InvariantChecks = std::tuple<
@@ -724,8 +700,7 @@ using InvariantChecks = std::tuple<
ValidClawback,
ValidMPTIssuance,
ValidPermissionedDomain,
ValidAMM,
ValidLockedBalance>;
ValidAMM>;
/**
* @brief get a tuple of all invariant checks

View File

@@ -573,7 +573,7 @@ Payment::doApply()
return tecUNFUNDED_PAYMENT;
}
// AMMs can never receive an XAH payment.
// AMMs can never receive an XRP payment.
// Must use AMMDeposit transaction instead.
if (sleDst->isFieldPresent(sfAMMID))
return tecNO_PERMISSION;

View File

@@ -295,11 +295,6 @@ Remit::doApply()
(flags & lsfDisallowIncomingRemit))
return tecNO_PERMISSION;
// AMMs can never receive an XAH payment.
// Must use AMMDeposit transaction instead.
if (sleDstAcc && sleDstAcc->isFieldPresent(sfAMMID))
return tecNO_PERMISSION;
// Check if the destination account requires deposit authorization.
bool const depositAuth{sb.rules().enabled(featureDepositAuth)};
if (depositAuth && sleDstAcc && (flags & lsfDepositAuth))

View File

@@ -425,7 +425,7 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj)
JLOG(ctx.j.trace())
<< "HookSet(" << hook::log::NAMESPACE_MISSING << ")["
<< HS_ACC()
<< "]: Malformed transaction: SetHook ltHookDefinition "
<< "]: Malformed transaction: SetHook sfHookDefinition "
"must contain sfHookNamespace.";
return false;
}
@@ -2001,7 +2001,7 @@ SetHook::setHook()
// sfHookHash, sfHookNamespace, sfHookOn, sfHookOnOutgoing,
// sfHookOnIncoming, sfHookCanEmit sfHookApiVersion, sfFlags: free
// ltHookDefinition is not reserved because it is an unowned object,
// sfHookDefinition is not reserved because it is an unowned object,
// rather the uploader is billed via fee according to the following:
// sfCreateCode: 5000 drops per byte
// sfHookParameters: 5000 drops per byte

View File

@@ -308,7 +308,7 @@ Transactor::calculateBaseFee(ReadView const& view, STTx const& tx)
// * The additional cost of each multisignature on the transaction.
XRPAmount baseFee = view.fees().base;
if (tx.getTxnType() == ttIMPORT)
if (tx.getFieldU16(sfTransactionType) == ttIMPORT)
{
XRPAmount const importFee = baseFee * 10;
if (importFee > baseFee)
@@ -325,7 +325,7 @@ Transactor::calculateBaseFee(ReadView const& view, STTx const& tx)
if (view.rules().enabled(featureHooks))
{
// if this is a "cleanup" txn we regard it as already paid up
if (tx.getTxnType() == ttEMIT_FAILURE)
if (tx.getFieldU16(sfTransactionType) == ttEMIT_FAILURE)
return XRPAmount{0};
// if the txn is an emitted txn then we add the callback fee
@@ -1536,7 +1536,10 @@ Transactor::doHookCallback(
true,
true,
false,
ctx_.tx.getTxnType() == ttEMIT_FAILURE ? 1UL : 0UL,
safe_cast<TxType>(ctx_.tx.getFieldU16(sfTransactionType)) ==
ttEMIT_FAILURE
? 1UL
: 0UL,
hook_no - 1,
provisionalMeta);

View File

@@ -180,7 +180,7 @@ URIToken::preclaim(PreclaimContext const& ctx)
}
AccountID const acc = ctx.tx.getAccountID(sfAccount);
TxType const& tt = ctx.tx.getTxnType();
uint16_t tt = ctx.tx.getFieldU16(sfTransactionType);
auto const sle =
ctx.view.read(keylet::account(ctx.tx.getAccountID(sfAccount)));
@@ -349,7 +349,7 @@ URIToken::doApply()
if (!sle)
return tefINTERNAL;
TxType const& tt = ctx_.tx.getTxnType();
uint16_t tt = ctx_.tx.getFieldU16(sfTransactionType);
if (tt == ttURITOKEN_MINT || tt == ttURITOKEN_BUY)
{

View File

@@ -65,7 +65,7 @@ computeBookChanges(std::shared_ptr<L const> const& lpAccepted)
continue;
std::optional<uint32_t> offerCancel;
TxType const& tt = tx.first->getTxnType();
uint16_t tt = tx.first->getFieldU16(sfTransactionType);
switch (tt)
{
case ttOFFER_CANCEL:

View File

@@ -32,7 +32,7 @@
#include <xrpl/protocol/digest.h>
#include <xrpl/protocol/jss.h>
#include <boost/algorithm/string.hpp>
#include <magic_enum.hpp>
#include <magic/magic_enum.h>
#include <sstream>
#define MAGIC_ENUM(x, _min, _max) \