From 921e97832ad89f723eeb01f69598000b100ae42f Mon Sep 17 00:00:00 2001 From: Shawn Xie <35279399+shawnxie999@users.noreply.github.com> Date: Thu, 19 Sep 2024 02:25:35 -0400 Subject: [PATCH] Chang UINT64 amounts to base 10 display (#35) * MPT amount base 10 * add assert * revert formatting * test * add test for maxamt * clang * parse as base 10 for all mpt amounts --- src/libxrpl/protocol/STInteger.cpp | 24 ++++++++++++++++----- src/libxrpl/protocol/STParsedJSON.cpp | 10 ++++++++- src/test/app/MPToken_test.cpp | 30 ++++++++++++++++++++------- src/test/jtx/impl/mpt.cpp | 13 +----------- src/test/jtx/mpt.h | 2 +- 5 files changed, 52 insertions(+), 27 deletions(-) diff --git a/src/libxrpl/protocol/STInteger.cpp b/src/libxrpl/protocol/STInteger.cpp index 7b7420006f9..148a05d2ab6 100644 --- a/src/libxrpl/protocol/STInteger.cpp +++ b/src/libxrpl/protocol/STInteger.cpp @@ -194,11 +194,25 @@ STUInt64::getText() const template <> Json::Value STUInt64::getJson(JsonOptions) const { - std::string str(16, 0); - auto ret = std::to_chars(str.data(), str.data() + str.size(), value_, 16); - assert(ret.ec == std::errc()); - str.resize(std::distance(str.data(), ret.ptr)); - return str; + auto convertToString = [](uint64_t const value, int const base) { + assert(base == 10 || base == 16); + std::string str( + base == 10 ? 20 : 16, 0); // Allocate space depending on base + auto ret = + std::to_chars(str.data(), str.data() + str.size(), value, base); + assert(ret.ec == std::errc()); + str.resize(std::distance(str.data(), ret.ptr)); + return str; + }; + + if (auto const& fName = getFName(); fName == sfMaximumAmount || + fName == sfOutstandingAmount || fName == sfLockedAmount || + fName == sfMPTAmount) + { + return convertToString(value_, 10); // Convert to base 10 + } + + return convertToString(value_, 16); // Convert to base 16 } } // namespace ripple diff --git a/src/libxrpl/protocol/STParsedJSON.cpp b/src/libxrpl/protocol/STParsedJSON.cpp index 92044334431..b8c74becf3d 100644 --- a/src/libxrpl/protocol/STParsedJSON.cpp +++ b/src/libxrpl/protocol/STParsedJSON.cpp @@ -398,8 +398,16 @@ parseLeaf( std::uint64_t val; + bool const useBase10 = field == sfMaximumAmount || + field == sfOutstandingAmount || + field == sfLockedAmount || field == sfMPTAmount; + + // if the field is amount, serialize as base 10 auto [p, ec] = std::from_chars( - str.data(), str.data() + str.size(), val, 16); + str.data(), + str.data() + str.size(), + val, + useBase10 ? 10 : 16); if (ec != std::errc() || (p != str.data() + str.size())) Throw("invalid data"); diff --git a/src/test/app/MPToken_test.cpp b/src/test/app/MPToken_test.cpp index 029ddc214b0..1a403ba79a9 100644 --- a/src/test/app/MPToken_test.cpp +++ b/src/test/app/MPToken_test.cpp @@ -53,7 +53,7 @@ class MPToken_test : public beast::unit_test::suite // tries to set a txfee while not enabling in the flag mptAlice.create( - {.maxAmt = 100, + {.maxAmt = "100", .assetScale = 0, .transferFee = 1, .metadata = "test", @@ -61,7 +61,7 @@ class MPToken_test : public beast::unit_test::suite // tries to set a txfee greater than max mptAlice.create( - {.maxAmt = 100, + {.maxAmt = "100", .assetScale = 0, .transferFee = maxTransferFee + 1, .metadata = "test", @@ -70,7 +70,7 @@ class MPToken_test : public beast::unit_test::suite // tries to set a txfee while not enabling transfer mptAlice.create( - {.maxAmt = 100, + {.maxAmt = "100", .assetScale = 0, .transferFee = maxTransferFee, .metadata = "test", @@ -78,7 +78,7 @@ class MPToken_test : public beast::unit_test::suite // empty metadata returns error mptAlice.create( - {.maxAmt = 100, + {.maxAmt = "100", .assetScale = 0, .transferFee = 0, .metadata = "", @@ -86,7 +86,7 @@ class MPToken_test : public beast::unit_test::suite // MaximumAmout of 0 returns error mptAlice.create( - {.maxAmt = 0, + {.maxAmt = "0", .assetScale = 1, .transferFee = 1, .metadata = "test", @@ -94,7 +94,13 @@ class MPToken_test : public beast::unit_test::suite // MaximumAmount larger than 63 bit returns error mptAlice.create( - {.maxAmt = 0xFFFFFFFFFFFFFFF0ull, + {.maxAmt = "18446744073709551600", // FFFFFFFFFFFFFFF0 + .assetScale = 0, + .transferFee = 0, + .metadata = "test", + .err = temMALFORMED}); + mptAlice.create( + {.maxAmt = "9223372036854775808", // 8000000000000000 .assetScale = 0, .transferFee = 0, .metadata = "test", @@ -116,13 +122,21 @@ class MPToken_test : public beast::unit_test::suite Env env{*this, features}; MPTTester mptAlice(env, alice); mptAlice.create( - {.maxAmt = 0x7FFFFFFFFFFFFFFF, + {.maxAmt = "9223372036854775807", // 7FFFFFFFFFFFFFFF .assetScale = 1, .transferFee = 10, .metadata = "123", .ownerCount = 1, .flags = tfMPTCanLock | tfMPTRequireAuth | tfMPTCanEscrow | tfMPTCanTrade | tfMPTCanTransfer | tfMPTCanClawback}); + + // Get the hash for the most recent transaction. + std::string const txHash{ + env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; + + Json::Value const result = env.rpc("tx", txHash)[jss::result]; + BEAST_EXPECT( + result[sfMaximumAmount.getJsonName()] == "9223372036854775807"); } } @@ -781,7 +795,7 @@ class MPToken_test : public beast::unit_test::suite MPTTester mptAlice(env, alice, {.holders = {&bob}}); mptAlice.create( - {.maxAmt = 100, + {.maxAmt = "100", .ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); diff --git a/src/test/jtx/impl/mpt.cpp b/src/test/jtx/impl/mpt.cpp index 88f206796bf..1e051a8092a 100644 --- a/src/test/jtx/impl/mpt.cpp +++ b/src/test/jtx/impl/mpt.cpp @@ -25,15 +25,6 @@ namespace ripple { namespace test { namespace jtx { -static std::array -uint64ToByteArray(std::uint64_t value) -{ - value = boost::endian::native_to_big(value); - std::array result; - std::memcpy(result.data(), &value, sizeof(value)); - return result; -} - void mptflags::operator()(Env& env) const { @@ -105,10 +96,8 @@ MPTTester::create(const MPTCreate& arg) jv[sfTransferFee.jsonName] = *arg.transferFee; if (arg.metadata) jv[sfMPTokenMetadata.jsonName] = strHex(*arg.metadata); - - // convert maxAmt to hex string, since json doesn't accept 64-bit int if (arg.maxAmt) - jv[sfMaximumAmount.jsonName] = strHex(uint64ToByteArray(*arg.maxAmt)); + jv[sfMaximumAmount.jsonName] = *arg.maxAmt; if (submit(arg, jv) != tesSUCCESS) { // Verify issuance doesn't exist diff --git a/src/test/jtx/mpt.h b/src/test/jtx/mpt.h index e96b73f039a..78b09a03923 100644 --- a/src/test/jtx/mpt.h +++ b/src/test/jtx/mpt.h @@ -97,7 +97,7 @@ struct MPTConstr struct MPTCreate { - std::optional maxAmt = std::nullopt; + std::optional maxAmt = std::nullopt; std::optional assetScale = std::nullopt; std::optional transferFee = std::nullopt; std::optional metadata = std::nullopt;