Compare commits

...

9 Commits

Author SHA1 Message Date
Pratik Mankawde
060eff0cf4 removed amendmend code
Signed-off-by: Pratik Mankawde <pmankawde@ripple.com>
2025-10-29 10:50:00 +00:00
Pratik Mankawde
0a41305a75 removed from feature file
Signed-off-by: Pratik Mankawde <pmankawde@ripple.com>
2025-10-28 16:04:43 +00:00
Pratik Mankawde
d9960d5ba0 refactor: Retire fix1543 amendment (#5926)
Amendments activated for more than 2 years can be retired. This change retires the fix1543 amendment.

Co-authored-by: Bart Thomee <11445373+bthomee@users.noreply.github.com>
2025-10-28 15:10:38 +00:00
Ayaz Salikhov
91fa6b2295 ci: Only run .exe files during test phase on Windows (#5947) 2025-10-28 14:26:25 +00:00
Jingchen
76f774e22d refactor: Migrate json unit tests to use doctest (#5533)
Co-authored-by: Bart Thomee <11445373+bthomee@users.noreply.github.com>
2025-10-28 14:19:39 +00:00
Shawn Xie
f4f7618173 Change fixMPTDeliveredAmount to Supported::yes (#5833)
Co-authored-by: Bart Thomee <11445373+bthomee@users.noreply.github.com>
2025-10-27 19:04:14 +00:00
Ayaz Salikhov
66f16469f9 fix: Upload all test binaries (#5932) 2025-10-27 17:27:56 +00:00
Ayaz Salikhov
1845b1c656 chore: Better pre-commit failure message (#5940) 2025-10-27 14:43:45 +00:00
Ayaz Salikhov
e192ffe964 fix: Clean up build profile options (#5934)
The `-Wno-missing-template-arg-list-after-template-kw` flag is only needed for the grpc library. Use `+=` for the default build flags to make it easier to extend in the future.

Co-authored-by: Bart Thomee <11445373+bthomee@users.noreply.github.com>
2025-10-24 15:16:15 +00:00
21 changed files with 1644 additions and 1917 deletions

View File

@@ -138,6 +138,7 @@ test.toplevel > test.csf
test.toplevel > xrpl.json
test.unit_test > xrpl.basics
tests.libxrpl > xrpl.basics
tests.libxrpl > xrpl.json
tests.libxrpl > xrpl.net
xrpl.json > xrpl.basics
xrpl.ledger > xrpl.basics

View File

@@ -9,7 +9,7 @@ on:
jobs:
# Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks.
run-hooks:
uses: XRPLF/actions/.github/workflows/pre-commit.yml@a8d7472b450eb53a1e5228f64552e5974457a21a
uses: XRPLF/actions/.github/workflows/pre-commit.yml@34790936fae4c6c751f62ec8c06696f9c1a5753a
with:
runs_on: ubuntu-latest
container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit:sha-a8c7be1" }'

View File

@@ -101,11 +101,27 @@ jobs:
--parallel $(nproc) \
--target "${CMAKE_TARGET}"
- name: Put built binaries in one location
shell: bash
working-directory: ${{ inputs.build_dir }}
env:
BUILD_TYPE_DIR: ${{ runner.os == 'Windows' && inputs.build_type || '' }}
CMAKE_TARGET: ${{ inputs.cmake_target }}
run: |
mkdir -p ./binaries/doctest/
cp ./${BUILD_TYPE_DIR}/rippled* ./binaries/
if [ "${CMAKE_TARGET}" != 'coverage' ]; then
cp ./src/tests/libxrpl/${BUILD_TYPE_DIR}/xrpl.test.* ./binaries/doctest/
fi
- name: Upload rippled artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
env:
BUILD_DIR: ${{ inputs.build_dir }}
with:
name: rippled-${{ inputs.config_name }}
path: ${{ inputs.build_dir }}/${{ runner.os == 'Windows' && inputs.build_type || '' }}/rippled${{ runner.os == 'Windows' && '.exe' || '' }}
path: ${{ env.BUILD_DIR }}/binaries/
retention-days: 3
if-no-files-found: error

View File

@@ -33,6 +33,10 @@ jobs:
container: ${{ inputs.image != '' && inputs.image || null }}
timeout-minutes: 30
steps:
- name: Cleanup workspace
if: ${{ runner.os == 'macOS' }}
uses: XRPLF/actions/.github/actions/cleanup-workspace@3f044c7478548e3c32ff68980eeb36ece02b364e
- name: Download rippled artifact
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
@@ -62,9 +66,24 @@ jobs:
run: |
./rippled --version | grep libvoidstar
- name: Test the binary
- name: Run the embedded tests
if: ${{ inputs.run_tests }}
shell: bash
run: |
./rippled --unittest --unittest-jobs $(nproc)
ctest -j $(nproc) --output-on-failure
- name: Run the separate tests
if: ${{ inputs.run_tests }}
env:
EXT: ${{ runner.os == 'Windows' && '.exe' || '' }}
shell: bash
run: |
for test_file in ./doctest/*${EXT}; do
echo "Executing $test_file"
chmod +x "$test_file"
if [[ "${{ runner.os }}" == "Windows" && "$test_file" == "./doctest/xrpl.test.net.exe" ]]; then
echo "Skipping $test_file on Windows"
else
"$test_file"
fi
done

View File

@@ -7,7 +7,7 @@ function(xrpl_add_test name)
"${CMAKE_CURRENT_SOURCE_DIR}/${name}/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/${name}.cpp"
)
add_executable(${target} EXCLUDE_FROM_ALL ${ARGN} ${sources})
add_executable(${target} ${ARGN} ${sources})
isolate_headers(
${target}

View File

@@ -21,11 +21,11 @@ compiler.libcxx={{detect_api.detect_libcxx(compiler, version, compiler_exe)}}
[conf]
{% if compiler == "clang" and compiler_version >= 19 %}
tools.build:cxxflags=['-Wno-missing-template-arg-list-after-template-kw']
grpc/1.50.1:tools.build:cxxflags+=['-Wno-missing-template-arg-list-after-template-kw']
{% endif %}
{% if compiler == "apple-clang" and compiler_version >= 17 %}
tools.build:cxxflags=['-Wno-missing-template-arg-list-after-template-kw']
grpc/1.50.1:tools.build:cxxflags+=['-Wno-missing-template-arg-list-after-template-kw']
{% endif %}
{% if compiler == "gcc" and compiler_version < 13 %}
tools.build:cxxflags=['-Wno-restrict']
tools.build:cxxflags+=['-Wno-restrict']
{% endif %}

View File

@@ -211,18 +211,13 @@ constexpr std::uint32_t const tfMPTokenIssuanceDestroyMask = ~tfUniversal;
// issuer's reserve without bound.
//
// The fixRemoveNFTokenAutoTrustLine amendment disables minting with the
// tfTrustLine flag as a way to prevent the attack. But until the
// amendment passes we still need to keep the old behavior available.
// tfTrustLine flag as a way to prevent the attack. Since the amendment
// has passed, we don't include tfTrustLine flag in tfNFTokenMintMask anymore.
constexpr std::uint32_t const tfNFTokenMintMask =
~(tfUniversal | tfBurnable | tfOnlyXRP | tfTransferable);
constexpr std::uint32_t const tfNFTokenMintOldMask =
~( ~tfNFTokenMintMask | tfTrustLine);
// if featureDynamicNFT enabled then new flag allowing mutable URI available.
constexpr std::uint32_t const tfNFTokenMintOldMaskWithMutable =
~( ~tfNFTokenMintOldMask | tfMutable);
// if featureDynamicNFT enabled then flag allowing mutable URI available.
constexpr std::uint32_t const tfNFTokenMintMaskWithMutable =
~( ~tfNFTokenMintMask | tfMutable);

View File

@@ -37,7 +37,7 @@ XRPL_FEATURE(DynamicMPT, Supported::no, VoteBehavior::DefaultNo
XRPL_FIX (TokenEscrowV1, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (DelegateV1_1, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (PriceOracleOrder, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (MPTDeliveredAmount, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (MPTDeliveredAmount, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (AMMClawbackRounding, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(TokenEscrow, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (EnforceNFTokenTrustlineV2, Supported::yes, VoteBehavior::DefaultNo)
@@ -86,7 +86,6 @@ XRPL_FIX (UniversalNumber, Supported::yes, VoteBehavior::DefaultNo
XRPL_FEATURE(XRPFees, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(DisallowIncoming, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(ImmediateOfferKilled, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (RemoveNFTokenAutoTrustLine, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (TrustLinesToSelf, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(NonFungibleTokensV1_1, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(ExpandedSignerList, Supported::yes, VoteBehavior::DefaultNo)
@@ -111,7 +110,6 @@ XRPL_FEATURE(MultiSignReserve, Supported::yes, VoteBehavior::DefaultYe
XRPL_FIX (1578, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(DepositPreauth, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (1623, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (1543, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (1571, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(Checks, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(DepositAuth, Supported::yes, VoteBehavior::DefaultYes)
@@ -155,3 +153,5 @@ XRPL_RETIRE(fix1528)
XRPL_RETIRE(FlowCross)
XRPL_RETIRE(fix1513)
XRPL_RETIRE(fix1515)
XRPL_RETIRE(fix1543)
XRPL_RETIRE(fixRemoveNFTokenAutoTrustLine)

View File

@@ -1621,180 +1621,78 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite
IOU const gwCAD(gw["CAD"]);
IOU const gwEUR(gw["EUR"]);
// The behavior of this test changes dramatically based on the
// presence (or absence) of the fixRemoveNFTokenAutoTrustLine
// amendment. So we test both cases here.
for (auto const& tweakedFeatures :
{features - fixRemoveNFTokenAutoTrustLine,
features | fixRemoveNFTokenAutoTrustLine})
Env env{*this, features};
env.fund(XRP(1000), alice, becky, cheri, gw);
env.close();
// Set trust lines so becky and cheri can use gw's currency.
env(trust(becky, gwAUD(1000)));
env(trust(cheri, gwAUD(1000)));
env(trust(becky, gwCAD(1000)));
env(trust(cheri, gwCAD(1000)));
env(trust(becky, gwEUR(1000)));
env(trust(cheri, gwEUR(1000)));
env.close();
env(pay(gw, becky, gwAUD(500)));
env(pay(gw, becky, gwCAD(500)));
env(pay(gw, becky, gwEUR(500)));
env(pay(gw, cheri, gwAUD(500)));
env(pay(gw, cheri, gwCAD(500)));
env.close();
// An nft without flagCreateTrustLines but with a non-zero transfer
// fee will not allow creating offers that use IOUs for payment.
for (std::uint32_t xferFee : {0, 1})
{
Env env{*this, tweakedFeatures};
env.fund(XRP(1000), alice, becky, cheri, gw);
uint256 const nftNoAutoTrustID{
token::getNextID(env, alice, 0u, tfTransferable, xferFee)};
env(token::mint(alice, 0u),
token::xferFee(xferFee),
txflags(tfTransferable));
env.close();
// Set trust lines so becky and cheri can use gw's currency.
env(trust(becky, gwAUD(1000)));
env(trust(cheri, gwAUD(1000)));
env(trust(becky, gwCAD(1000)));
env(trust(cheri, gwCAD(1000)));
env(trust(becky, gwEUR(1000)));
env(trust(cheri, gwEUR(1000)));
// becky buys the nft for 1 drop.
uint256 const beckyBuyOfferIndex =
keylet::nftoffer(becky, env.seq(becky)).key;
env(token::createOffer(becky, nftNoAutoTrustID, drops(1)),
token::owner(alice));
env.close();
env(pay(gw, becky, gwAUD(500)));
env(pay(gw, becky, gwCAD(500)));
env(pay(gw, becky, gwEUR(500)));
env(pay(gw, cheri, gwAUD(500)));
env(pay(gw, cheri, gwCAD(500)));
env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
env.close();
// An nft without flagCreateTrustLines but with a non-zero transfer
// fee will not allow creating offers that use IOUs for payment.
for (std::uint32_t xferFee : {0, 1})
{
uint256 const nftNoAutoTrustID{
token::getNextID(env, alice, 0u, tfTransferable, xferFee)};
env(token::mint(alice, 0u),
token::xferFee(xferFee),
txflags(tfTransferable));
env.close();
// becky attempts to sell the nft for AUD.
TER const createOfferTER =
xferFee ? TER(tecNO_LINE) : TER(tesSUCCESS);
uint256 const beckyOfferIndex =
keylet::nftoffer(becky, env.seq(becky)).key;
env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)),
txflags(tfSellNFToken),
ter(createOfferTER));
env.close();
// becky buys the nft for 1 drop.
uint256 const beckyBuyOfferIndex =
keylet::nftoffer(becky, env.seq(becky)).key;
env(token::createOffer(becky, nftNoAutoTrustID, drops(1)),
token::owner(alice));
env.close();
env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
env.close();
// cheri offers to buy the nft for CAD.
uint256 const cheriOfferIndex =
keylet::nftoffer(cheri, env.seq(cheri)).key;
env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
token::owner(becky),
ter(createOfferTER));
env.close();
// becky attempts to sell the nft for AUD.
TER const createOfferTER =
xferFee ? TER(tecNO_LINE) : TER(tesSUCCESS);
uint256 const beckyOfferIndex =
keylet::nftoffer(becky, env.seq(becky)).key;
env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)),
txflags(tfSellNFToken),
ter(createOfferTER));
env.close();
// cheri offers to buy the nft for CAD.
uint256 const cheriOfferIndex =
keylet::nftoffer(cheri, env.seq(cheri)).key;
env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
token::owner(becky),
ter(createOfferTER));
env.close();
// To keep things tidy, cancel the offers.
env(token::cancelOffer(becky, {beckyOfferIndex}));
env(token::cancelOffer(cheri, {cheriOfferIndex}));
env.close();
}
// An nft with flagCreateTrustLines but with a non-zero transfer
// fee allows transfers using IOUs for payment.
{
std::uint16_t transferFee = 10000; // 10%
uint256 const nftAutoTrustID{token::getNextID(
env, alice, 0u, tfTransferable | tfTrustLine, transferFee)};
// If the fixRemoveNFTokenAutoTrustLine amendment is active
// then this transaction fails.
{
TER const mintTER =
tweakedFeatures[fixRemoveNFTokenAutoTrustLine]
? static_cast<TER>(temINVALID_FLAG)
: static_cast<TER>(tesSUCCESS);
env(token::mint(alice, 0u),
token::xferFee(transferFee),
txflags(tfTransferable | tfTrustLine),
ter(mintTER));
env.close();
// If fixRemoveNFTokenAutoTrustLine is active the rest
// of this test falls on its face.
if (tweakedFeatures[fixRemoveNFTokenAutoTrustLine])
break;
}
// becky buys the nft for 1 drop.
uint256 const beckyBuyOfferIndex =
keylet::nftoffer(becky, env.seq(becky)).key;
env(token::createOffer(becky, nftAutoTrustID, drops(1)),
token::owner(alice));
env.close();
env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
env.close();
// becky sells the nft for AUD.
uint256 const beckySellOfferIndex =
keylet::nftoffer(becky, env.seq(becky)).key;
env(token::createOffer(becky, nftAutoTrustID, gwAUD(100)),
txflags(tfSellNFToken));
env.close();
env(token::acceptSellOffer(cheri, beckySellOfferIndex));
env.close();
// alice should now have a trust line for gwAUD.
BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
// becky buys the nft back for CAD.
uint256 const beckyBuyBackOfferIndex =
keylet::nftoffer(becky, env.seq(becky)).key;
env(token::createOffer(becky, nftAutoTrustID, gwCAD(50)),
token::owner(cheri));
env.close();
env(token::acceptBuyOffer(cheri, beckyBuyBackOfferIndex));
env.close();
// alice should now have a trust line for gwAUD and gwCAD.
BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(5));
}
// Now that alice has trust lines preestablished, an nft without
// flagCreateTrustLines will work for preestablished trust lines.
{
std::uint16_t transferFee = 5000; // 5%
uint256 const nftNoAutoTrustID{token::getNextID(
env, alice, 0u, tfTransferable, transferFee)};
env(token::mint(alice, 0u),
token::xferFee(transferFee),
txflags(tfTransferable));
env.close();
// alice sells the nft using AUD.
uint256 const aliceSellOfferIndex =
keylet::nftoffer(alice, env.seq(alice)).key;
env(token::createOffer(alice, nftNoAutoTrustID, gwAUD(200)),
txflags(tfSellNFToken));
env.close();
env(token::acceptSellOffer(cheri, aliceSellOfferIndex));
env.close();
// alice should now have AUD(210):
// o 200 for this sale and
// o 10 for the previous sale's fee.
BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(210));
// cheri can't sell the NFT for EUR, but can for CAD.
env(token::createOffer(cheri, nftNoAutoTrustID, gwEUR(50)),
txflags(tfSellNFToken),
ter(tecNO_LINE));
env.close();
uint256 const cheriSellOfferIndex =
keylet::nftoffer(cheri, env.seq(cheri)).key;
env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
txflags(tfSellNFToken));
env.close();
env(token::acceptSellOffer(becky, cheriSellOfferIndex));
env.close();
// alice should now have CAD(10):
// o 5 from this sale's fee and
// o 5 for the previous sale's fee.
BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(10));
}
// To keep things tidy, cancel the offers.
env(token::cancelOffer(becky, {beckyOfferIndex}));
env(token::cancelOffer(cheri, {cheriOfferIndex}));
env.close();
}
// An nft with flagCreateTrustLines but with a non-zero transfer
// fee allows transfers using IOUs for payment.
std::uint16_t transferFee = 10000; // 10%
env(token::mint(alice, 0u),
token::xferFee(transferFee),
txflags(tfTransferable | tfTrustLine),
ter(static_cast<TER>(temINVALID_FLAG)));
env.close();
}
void
@@ -7433,12 +7331,12 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite
// https://github.com/XRPLF/rippled/issues/4925
//
// For an NFToken with a transfer fee, the issuer must be able to
// accept the transfer fee or else a transfer should fail. If the
// accept the transfer fee or else a transfer should fail. If the
// NFToken is transferred for a non-XRP asset, then the issuer must
// have a trustline to that asset to receive the fee.
//
// This test looks at a situation where issuer would get a trustline
// for the fee without the issuer's consent. Here are the steps:
// for the fee without the issuer's consent. Here are the steps:
// 1. Issuer has a trustline (i.e., USD)
// 2. Issuer mints NFToken with transfer fee.
// 3. Becky acquires the NFToken, paying with XRP.
@@ -7456,8 +7354,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite
//
// In both cases we remove the fixRemoveNFTokenAutoTrustLine amendment.
// Otherwise we can't create NFTokens with tfTrustLine enabled.
FeatureBitset const localFeatures =
features - fixRemoveNFTokenAutoTrustLine;
FeatureBitset const localFeatures = features;
for (FeatureBitset feats :
{localFeatures - fixEnforceNFTokenTrustline,
localFeatures | fixEnforceNFTokenTrustline})
@@ -7627,8 +7524,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite
//
// We remove the fixRemoveNFTokenAutoTrustLine amendment. Otherwise
// we can't create NFTokens with tfTrustLine enabled.
FeatureBitset const localFeatures =
features - fixRemoveNFTokenAutoTrustLine;
FeatureBitset const localFeatures = features;
Env env{*this, localFeatures};
env.fund(XRP(1000), issuer, becky, cheri);

View File

@@ -1,217 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <test/json/TestOutputSuite.h>
#include <xrpl/beast/unit_test.h>
#include <xrpl/json/Writer.h>
namespace Json {
class JsonWriter_test : public ripple::test::TestOutputSuite
{
public:
void
testTrivial()
{
setup("trivial");
BEAST_EXPECT(output_.empty());
expectResult("");
}
void
testNearTrivial()
{
setup("near trivial");
BEAST_EXPECT(output_.empty());
writer_->output(0);
expectResult("0");
}
void
testPrimitives()
{
setup("true");
writer_->output(true);
expectResult("true");
setup("false");
writer_->output(false);
expectResult("false");
setup("23");
writer_->output(23);
expectResult("23");
setup("23.0");
writer_->output(23.0);
expectResult("23.0");
setup("23.5");
writer_->output(23.5);
expectResult("23.5");
setup("a string");
writer_->output("a string");
expectResult("\"a string\"");
setup("nullptr");
writer_->output(nullptr);
expectResult("null");
}
void
testEmpty()
{
setup("empty array");
writer_->startRoot(Writer::array);
writer_->finish();
expectResult("[]");
setup("empty object");
writer_->startRoot(Writer::object);
writer_->finish();
expectResult("{}");
}
void
testEscaping()
{
setup("backslash");
writer_->output("\\");
expectResult("\"\\\\\"");
setup("quote");
writer_->output("\"");
expectResult("\"\\\"\"");
setup("backslash and quote");
writer_->output("\\\"");
expectResult("\"\\\\\\\"\"");
setup("escape embedded");
writer_->output("this contains a \\ in the middle of it.");
expectResult("\"this contains a \\\\ in the middle of it.\"");
setup("remaining escapes");
writer_->output("\b\f\n\r\t");
expectResult("\"\\b\\f\\n\\r\\t\"");
}
void
testArray()
{
setup("empty array");
writer_->startRoot(Writer::array);
writer_->append(12);
writer_->finish();
expectResult("[12]");
}
void
testLongArray()
{
setup("long array");
writer_->startRoot(Writer::array);
writer_->append(12);
writer_->append(true);
writer_->append("hello");
writer_->finish();
expectResult("[12,true,\"hello\"]");
}
void
testEmbeddedArraySimple()
{
setup("embedded array simple");
writer_->startRoot(Writer::array);
writer_->startAppend(Writer::array);
writer_->finish();
writer_->finish();
expectResult("[[]]");
}
void
testObject()
{
setup("object");
writer_->startRoot(Writer::object);
writer_->set("hello", "world");
writer_->finish();
expectResult("{\"hello\":\"world\"}");
}
void
testComplexObject()
{
setup("complex object");
writer_->startRoot(Writer::object);
writer_->set("hello", "world");
writer_->startSet(Writer::array, "array");
writer_->append(true);
writer_->append(12);
writer_->startAppend(Writer::array);
writer_->startAppend(Writer::object);
writer_->set("goodbye", "cruel world.");
writer_->startSet(Writer::array, "subarray");
writer_->append(23.5);
writer_->finishAll();
expectResult(
"{\"hello\":\"world\",\"array\":[true,12,"
"[{\"goodbye\":\"cruel world.\","
"\"subarray\":[23.5]}]]}");
}
void
testJson()
{
setup("object");
Json::Value value(Json::objectValue);
value["foo"] = 23;
writer_->startRoot(Writer::object);
writer_->set("hello", value);
writer_->finish();
expectResult("{\"hello\":{\"foo\":23}}");
}
void
run() override
{
testTrivial();
testNearTrivial();
testPrimitives();
testEmpty();
testEscaping();
testArray();
testLongArray();
testEmbeddedArraySimple();
testObject();
testComplexObject();
testJson();
}
};
BEAST_DEFINE_TESTSUITE(JsonWriter, json, ripple);
} // namespace Json

File diff suppressed because it is too large Load Diff

View File

@@ -12,5 +12,7 @@ xrpl_add_test(basics)
target_link_libraries(xrpl.test.basics PRIVATE xrpl.imports.test)
xrpl_add_test(crypto)
target_link_libraries(xrpl.test.crypto PRIVATE xrpl.imports.test)
xrpl_add_test(json)
target_link_libraries(xrpl.test.json PRIVATE xrpl.imports.test)
xrpl_add_test(net)
target_link_libraries(xrpl.test.net PRIVATE xrpl.imports.test)

View File

@@ -17,50 +17,43 @@
*/
//==============================================================================
#include <test/json/TestOutputSuite.h>
#include <xrpl/json/Output.h>
#include <xrpl/json/json_reader.h>
#include <xrpl/json/json_writer.h>
namespace Json {
#include <doctest/doctest.h>
struct Output_test : ripple::test::TestOutputSuite
#include <string>
using namespace ripple;
using namespace Json;
TEST_SUITE_BEGIN("JsonOutput");
static void
checkOutput(std::string const& valueDesc)
{
void
runTest(std::string const& name, std::string const& valueDesc)
{
setup(name);
Json::Value value;
BEAST_EXPECT(Json::Reader().parse(valueDesc, value));
auto out = stringOutput(output_);
outputJson(value, out);
std::string output;
Json::Value value;
REQUIRE(Json::Reader().parse(valueDesc, value));
auto out = stringOutput(output);
outputJson(value, out);
// Compare with the original version.
auto expected = Json::FastWriter().write(value);
expectResult(expected);
expectResult(valueDesc);
expectResult(jsonAsString(value));
}
auto expected = Json::FastWriter().write(value);
CHECK(output == expected);
CHECK(output == valueDesc);
CHECK(output == jsonAsString(value));
}
void
runTest(std::string const& name)
{
runTest(name, name);
}
TEST_CASE("output cases")
{
checkOutput("{}");
checkOutput("[]");
checkOutput(R"([23,4.25,true,null,"string"])");
checkOutput(R"({"hello":"world"})");
checkOutput("[{}]");
checkOutput("[[]]");
checkOutput(R"({"array":[{"12":23},{},null,false,0.5]})");
}
void
run() override
{
runTest("empty dict", "{}");
runTest("empty array", "[]");
runTest("array", "[23,4.25,true,null,\"string\"]");
runTest("dict", "{\"hello\":\"world\"}");
runTest("array dict", "[{}]");
runTest("array array", "[[]]");
runTest("more complex", "{\"array\":[{\"12\":23},{},null,false,0.5]}");
}
};
BEAST_DEFINE_TESTSUITE(Output, json, ripple);
} // namespace Json
TEST_SUITE_END();

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,192 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <xrpl/json/Writer.h>
#include <doctest/doctest.h>
#include <google/protobuf/stubs/port.h>
#include <memory>
#include <string>
using namespace ripple;
using namespace Json;
TEST_SUITE_BEGIN("JsonWriter");
struct WriterFixture
{
std::string output;
std::unique_ptr<Writer> writer;
WriterFixture()
{
writer = std::make_unique<Writer>(stringOutput(output));
}
void
reset()
{
output.clear();
writer = std::make_unique<Writer>(stringOutput(output));
}
void
expectOutput(std::string const& expected) const
{
CHECK(output == expected);
}
void
checkOutputAndReset(std::string const& expected)
{
expectOutput(expected);
reset();
}
};
TEST_CASE_FIXTURE(WriterFixture, "trivial")
{
CHECK(output.empty());
checkOutputAndReset("");
}
TEST_CASE_FIXTURE(WriterFixture, "near trivial")
{
CHECK(output.empty());
writer->output(0);
checkOutputAndReset("0");
}
TEST_CASE_FIXTURE(WriterFixture, "primitives")
{
writer->output(true);
checkOutputAndReset("true");
writer->output(false);
checkOutputAndReset("false");
writer->output(23);
checkOutputAndReset("23");
writer->output(23.0);
checkOutputAndReset("23.0");
writer->output(23.5);
checkOutputAndReset("23.5");
writer->output("a string");
checkOutputAndReset(R"("a string")");
writer->output(nullptr);
checkOutputAndReset("null");
}
TEST_CASE_FIXTURE(WriterFixture, "empty")
{
writer->startRoot(Writer::array);
writer->finish();
checkOutputAndReset("[]");
writer->startRoot(Writer::object);
writer->finish();
checkOutputAndReset("{}");
}
TEST_CASE_FIXTURE(WriterFixture, "escaping")
{
writer->output("\\");
checkOutputAndReset(R"("\\")");
writer->output("\"");
checkOutputAndReset(R"("\"")");
writer->output("\\\"");
checkOutputAndReset(R"("\\\"")");
writer->output("this contains a \\ in the middle of it.");
checkOutputAndReset(R"("this contains a \\ in the middle of it.")");
writer->output("\b\f\n\r\t");
checkOutputAndReset(R"("\b\f\n\r\t")");
}
TEST_CASE_FIXTURE(WriterFixture, "array")
{
writer->startRoot(Writer::array);
writer->append(12);
writer->finish();
checkOutputAndReset("[12]");
}
TEST_CASE_FIXTURE(WriterFixture, "long array")
{
writer->startRoot(Writer::array);
writer->append(12);
writer->append(true);
writer->append("hello");
writer->finish();
checkOutputAndReset(R"([12,true,"hello"])");
}
TEST_CASE_FIXTURE(WriterFixture, "embedded array simple")
{
writer->startRoot(Writer::array);
writer->startAppend(Writer::array);
writer->finish();
writer->finish();
checkOutputAndReset("[[]]");
}
TEST_CASE_FIXTURE(WriterFixture, "object")
{
writer->startRoot(Writer::object);
writer->set("hello", "world");
writer->finish();
checkOutputAndReset(R"({"hello":"world"})");
}
TEST_CASE_FIXTURE(WriterFixture, "complex object")
{
writer->startRoot(Writer::object);
writer->set("hello", "world");
writer->startSet(Writer::array, "array");
writer->append(true);
writer->append(12);
writer->startAppend(Writer::array);
writer->startAppend(Writer::object);
writer->set("goodbye", "cruel world.");
writer->startSet(Writer::array, "subarray");
writer->append(23.5);
writer->finishAll();
checkOutputAndReset(
R"({"hello":"world","array":[true,12,[{"goodbye":"cruel world.","subarray":[23.5]}]]})");
}
TEST_CASE_FIXTURE(WriterFixture, "json value")
{
Json::Value value(Json::objectValue);
value["foo"] = 23;
writer->startRoot(Writer::object);
writer->set("hello", value);
writer->finish();
checkOutputAndReset(R"({"hello":{"foo":23}})");
}
TEST_SUITE_END();

View File

@@ -0,0 +1,2 @@
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include <doctest/doctest.h>

View File

@@ -118,13 +118,6 @@ escrowCreatePreflightHelper<MPTIssue>(PreflightContext const& ctx)
return tesSUCCESS;
}
std::uint32_t
EscrowCreate::getFlagsMask(PreflightContext const& ctx)
{
// 0 means "Allow any flags"
return ctx.rules.enabled(fix1543) ? tfUniversalMask : 0;
}
NotTEC
EscrowCreate::preflight(PreflightContext const& ctx)
{
@@ -639,13 +632,6 @@ EscrowFinish::checkExtraFeatures(PreflightContext const& ctx)
ctx.rules.enabled(featureCredentials);
}
std::uint32_t
EscrowFinish::getFlagsMask(PreflightContext const& ctx)
{
// 0 means "Allow any flags"
return ctx.rules.enabled(fix1543) ? tfUniversalMask : 0;
}
NotTEC
EscrowFinish::preflight(PreflightContext const& ctx)
{
@@ -1225,13 +1211,6 @@ EscrowFinish::doApply()
//------------------------------------------------------------------------------
std::uint32_t
EscrowCancel::getFlagsMask(PreflightContext const& ctx)
{
// 0 means "Allow any flags"
return ctx.rules.enabled(fix1543) ? tfUniversalMask : 0;
}
NotTEC
EscrowCancel::preflight(PreflightContext const& ctx)
{

View File

@@ -36,9 +36,6 @@ public:
static TxConsequences
makeTxConsequences(PreflightContext const& ctx);
static std::uint32_t
getFlagsMask(PreflightContext const& ctx);
static NotTEC
preflight(PreflightContext const& ctx);
@@ -63,9 +60,6 @@ public:
static bool
checkExtraFeatures(PreflightContext const& ctx);
static std::uint32_t
getFlagsMask(PreflightContext const& ctx);
static NotTEC
preflight(PreflightContext const& ctx);
@@ -93,9 +87,6 @@ public:
{
}
static std::uint32_t
getFlagsMask(PreflightContext const& ctx);
static NotTEC
preflight(PreflightContext const& ctx);

View File

@@ -55,28 +55,11 @@ NFTokenMint::checkExtraFeatures(PreflightContext const& ctx)
std::uint32_t
NFTokenMint::getFlagsMask(PreflightContext const& ctx)
{
// Prior to fixRemoveNFTokenAutoTrustLine, transfer of an NFToken between
// accounts allowed a TrustLine to be added to the issuer of that token
// without explicit permission from that issuer. This was enabled by
// minting the NFToken with the tfTrustLine flag set.
//
// That capability could be used to attack the NFToken issuer. It
// would be possible for two accounts to trade the NFToken back and forth
// building up any number of TrustLines on the issuer, increasing the
// issuer's reserve without bound.
//
// The fixRemoveNFTokenAutoTrustLine amendment disables minting with the
// tfTrustLine flag as a way to prevent the attack. But until the
// amendment passes we still need to keep the old behavior available.
std::uint32_t const nfTokenMintMask =
ctx.rules.enabled(fixRemoveNFTokenAutoTrustLine)
// if featureDynamicNFT enabled then new flag allowing mutable URI
// available
? ctx.rules.enabled(featureDynamicNFT) ? tfNFTokenMintMaskWithMutable
: tfNFTokenMintMask
: ctx.rules.enabled(featureDynamicNFT) ? tfNFTokenMintOldMaskWithMutable
: tfNFTokenMintOldMask;
ctx.rules.enabled(featureDynamicNFT) ? tfNFTokenMintMaskWithMutable
: tfNFTokenMintMask;
return nfTokenMintMask;
}

View File

@@ -175,13 +175,6 @@ PayChanCreate::makeTxConsequences(PreflightContext const& ctx)
return TxConsequences{ctx.tx, ctx.tx[sfAmount].xrp()};
}
std::uint32_t
PayChanCreate::getFlagsMask(PreflightContext const& ctx)
{
// 0 means "Allow any flags"
return ctx.rules.enabled(fix1543) ? tfUniversalMask : 0;
}
NotTEC
PayChanCreate::preflight(PreflightContext const& ctx)
{
@@ -335,13 +328,6 @@ PayChanFund::makeTxConsequences(PreflightContext const& ctx)
return TxConsequences{ctx.tx, ctx.tx[sfAmount].xrp()};
}
std::uint32_t
PayChanFund::getFlagsMask(PreflightContext const& ctx)
{
// 0 means "Allow any flags"
return ctx.rules.enabled(fix1543) ? tfUniversalMask : 0;
}
NotTEC
PayChanFund::preflight(PreflightContext const& ctx)
{
@@ -434,10 +420,9 @@ PayChanClaim::checkExtraFeatures(PreflightContext const& ctx)
}
std::uint32_t
PayChanClaim::getFlagsMask(PreflightContext const& ctx)
PayChanClaim::getFlagsMask(PreflightContext const&)
{
// 0 means "Allow any flags"
return ctx.rules.enabled(fix1543) ? tfPayChanClaimMask : 0;
return tfPayChanClaimMask;
}
NotTEC

View File

@@ -36,9 +36,6 @@ public:
static TxConsequences
makeTxConsequences(PreflightContext const& ctx);
static std::uint32_t
getFlagsMask(PreflightContext const& ctx);
static NotTEC
preflight(PreflightContext const& ctx);
@@ -65,9 +62,6 @@ public:
static TxConsequences
makeTxConsequences(PreflightContext const& ctx);
static std::uint32_t
getFlagsMask(PreflightContext const& ctx);
static NotTEC
preflight(PreflightContext const& ctx);