mirror of
https://github.com/XRPLF/clio.git
synced 2026-09-27 15:38:04 +00:00
fix: Output format for MPT Issuance ID (#3178)
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
#include "rpc/Errors.hpp"
|
||||
#include "rpc/common/AnyHandler.hpp"
|
||||
#include "rpc/common/Types.hpp"
|
||||
#include "rpc/common/Validators.hpp"
|
||||
#include "rpc/handlers/AccountMPTokenIssuances.hpp"
|
||||
#include "util/HandlerBaseTestFixture.hpp"
|
||||
#include "util/NameGenerator.hpp"
|
||||
@@ -38,8 +39,8 @@ namespace {
|
||||
|
||||
constexpr auto kLedgerHash = "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652";
|
||||
constexpr auto kAccount = "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn";
|
||||
constexpr auto kIssuanceIndeX1 = "A6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC321";
|
||||
constexpr auto kIssuanceIndeX2 = "B6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC322";
|
||||
constexpr auto kIssuanceIndex1 = "A6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC321";
|
||||
constexpr auto kIssuanceIndex2 = "B6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC322";
|
||||
|
||||
// unique values for issuance1
|
||||
constexpr uint64_t kIssuancE1MaxAmount = 10000;
|
||||
@@ -57,6 +58,12 @@ constexpr auto kIssuancE2MetadataHex = "746573742D6D657461";
|
||||
constexpr auto kIssuancE2DomainIdHex =
|
||||
"E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC321";
|
||||
|
||||
[[nodiscard]] std::string
|
||||
expectedMptIssuanceId(std::uint32_t sequence)
|
||||
{
|
||||
return xrpl::to_string(xrpl::makeMptID(sequence, getAccountIdWithString(kAccount)));
|
||||
}
|
||||
|
||||
// define expected JSON for mpt issuances
|
||||
auto const kIssuanceOuT1 = fmt::format(
|
||||
R"JSON({{
|
||||
@@ -71,7 +78,7 @@ auto const kIssuanceOuT1 = fmt::format(
|
||||
"mpt_require_auth": true,
|
||||
"mpt_can_transfer": true
|
||||
}})JSON",
|
||||
kIssuanceIndeX1,
|
||||
expectedMptIssuanceId(1),
|
||||
kAccount,
|
||||
kIssuancE1MaxAmount,
|
||||
kIssuancE1OutstandingAmount,
|
||||
@@ -93,7 +100,7 @@ auto const kIssuanceOuT2 = fmt::format(
|
||||
"mpt_locked": true,
|
||||
"mpt_can_clawback": true
|
||||
}})JSON",
|
||||
kIssuanceIndeX2,
|
||||
expectedMptIssuanceId(2),
|
||||
kAccount,
|
||||
kIssuancE2MaxAmount,
|
||||
kIssuancE2OutstandingAmount,
|
||||
@@ -379,7 +386,7 @@ TEST_F(RPCAccountMPTokenIssuancesHandlerTest, DefaultParameters)
|
||||
|
||||
// return two mptoken issuance objects
|
||||
xrpl::STObject const ownerDir = createOwnerDirLedgerObject(
|
||||
{xrpl::uint256{kIssuanceIndeX1}, xrpl::uint256{kIssuanceIndeX2}}, kIssuanceIndeX1
|
||||
{xrpl::uint256{kIssuanceIndex1}, xrpl::uint256{kIssuanceIndex2}}, kIssuanceIndex1
|
||||
);
|
||||
ON_CALL(*backend_, doFetchLedgerObject(ownerDirKk, _, _))
|
||||
.WillByDefault(Return(ownerDir.getSerializer().peekData()));
|
||||
@@ -459,7 +466,7 @@ TEST_F(RPCAccountMPTokenIssuancesHandlerTest, UseLimit)
|
||||
ON_CALL(*backend_, doFetchLedgerObject(accountKk, _, _))
|
||||
.WillByDefault(Return(Blob{'f', 'a', 'k', 'e'}));
|
||||
|
||||
auto const indexes = std::vector<xrpl::uint256>(50, xrpl::uint256{kIssuanceIndeX1});
|
||||
auto const indexes = std::vector<xrpl::uint256>(50, xrpl::uint256{kIssuanceIndex1});
|
||||
auto const bbs = [&]() {
|
||||
std::vector<Blob> v;
|
||||
v.reserve(50);
|
||||
@@ -469,7 +476,7 @@ TEST_F(RPCAccountMPTokenIssuancesHandlerTest, UseLimit)
|
||||
return v;
|
||||
}();
|
||||
|
||||
xrpl::STObject ownerDir = createOwnerDirLedgerObject(indexes, kIssuanceIndeX1);
|
||||
xrpl::STObject ownerDir = createOwnerDirLedgerObject(indexes, kIssuanceIndex1);
|
||||
ownerDir.setFieldU64(xrpl::sfIndexNext, 99);
|
||||
ON_CALL(*backend_, doFetchLedgerObject(ownerDirKk, _, _))
|
||||
.WillByDefault(Return(ownerDir.getSerializer().peekData()));
|
||||
@@ -556,7 +563,7 @@ TEST_F(RPCAccountMPTokenIssuancesHandlerTest, MarkerOutput)
|
||||
.WillByDefault(Return(Blob{'f', 'a', 'k', 'e'}));
|
||||
EXPECT_CALL(*backend_, doFetchLedgerObject).Times(3);
|
||||
|
||||
auto const indexes = std::vector<xrpl::uint256>(10, xrpl::uint256{kIssuanceIndeX1});
|
||||
auto const indexes = std::vector<xrpl::uint256>(10, xrpl::uint256{kIssuanceIndex1});
|
||||
auto const bbs = [&]() {
|
||||
std::vector<Blob> v;
|
||||
v.reserve(kLimit);
|
||||
@@ -568,13 +575,13 @@ TEST_F(RPCAccountMPTokenIssuancesHandlerTest, MarkerOutput)
|
||||
EXPECT_CALL(*backend_, doFetchLedgerObjects).WillOnce(Return(bbs));
|
||||
|
||||
// mock the first directory page
|
||||
xrpl::STObject ownerDir1 = createOwnerDirLedgerObject(indexes, kIssuanceIndeX1);
|
||||
xrpl::STObject ownerDir1 = createOwnerDirLedgerObject(indexes, kIssuanceIndex1);
|
||||
ownerDir1.setFieldU64(xrpl::sfIndexNext, kNextPage);
|
||||
ON_CALL(*backend_, doFetchLedgerObject(ownerDirKk, _, _))
|
||||
.WillByDefault(Return(ownerDir1.getSerializer().peekData()));
|
||||
|
||||
// mock the second directory page
|
||||
xrpl::STObject ownerDir2 = createOwnerDirLedgerObject(indexes, kIssuanceIndeX2);
|
||||
xrpl::STObject ownerDir2 = createOwnerDirLedgerObject(indexes, kIssuanceIndex2);
|
||||
ownerDir2.setFieldU64(xrpl::sfIndexNext, 0);
|
||||
ON_CALL(*backend_, doFetchLedgerObject(ownerDir2Kk, _, _))
|
||||
.WillByDefault(Return(ownerDir2.getSerializer().peekData()));
|
||||
@@ -596,7 +603,7 @@ TEST_F(RPCAccountMPTokenIssuancesHandlerTest, MarkerOutput)
|
||||
auto const& resultJson = output.result->as_object();
|
||||
EXPECT_EQ(
|
||||
boost::json::value_to<std::string>(resultJson.at("marker")),
|
||||
fmt::format("{},{}", kIssuanceIndeX1, kNextPage)
|
||||
fmt::format("{},{}", kIssuanceIndex1, kNextPage)
|
||||
);
|
||||
EXPECT_EQ(resultJson.at("mpt_issuances").as_array().size(), kLimit);
|
||||
});
|
||||
@@ -617,7 +624,7 @@ TEST_F(RPCAccountMPTokenIssuancesHandlerTest, MarkerInput)
|
||||
.WillByDefault(Return(Blob{'f', 'a', 'k', 'e'}));
|
||||
EXPECT_CALL(*backend_, doFetchLedgerObject).Times(3);
|
||||
|
||||
auto const indexes = std::vector<xrpl::uint256>(kLimit, xrpl::uint256{kIssuanceIndeX1});
|
||||
auto const indexes = std::vector<xrpl::uint256>(kLimit, xrpl::uint256{kIssuanceIndex1});
|
||||
auto const bbs = [&]() {
|
||||
std::vector<Blob> v;
|
||||
v.reserve(kLimit);
|
||||
@@ -627,7 +634,7 @@ TEST_F(RPCAccountMPTokenIssuancesHandlerTest, MarkerInput)
|
||||
return v;
|
||||
}();
|
||||
|
||||
xrpl::STObject ownerDir = createOwnerDirLedgerObject(indexes, kIssuanceIndeX1);
|
||||
xrpl::STObject ownerDir = createOwnerDirLedgerObject(indexes, kIssuanceIndex1);
|
||||
ownerDir.setFieldU64(xrpl::sfIndexNext, 0);
|
||||
ON_CALL(*backend_, doFetchLedgerObject(ownerDirKk, _, _))
|
||||
.WillByDefault(Return(ownerDir.getSerializer().peekData()));
|
||||
@@ -644,7 +651,7 @@ TEST_F(RPCAccountMPTokenIssuancesHandlerTest, MarkerInput)
|
||||
}})JSON",
|
||||
kAccount,
|
||||
kLimit,
|
||||
kIssuanceIndeX1,
|
||||
kIssuanceIndex1,
|
||||
kNextPage
|
||||
)
|
||||
);
|
||||
@@ -670,7 +677,7 @@ TEST_F(RPCAccountMPTokenIssuancesHandlerTest, LimitLessThanMin)
|
||||
.WillOnce(Return(Blob{'f', 'a', 'k', 'e'}));
|
||||
|
||||
xrpl::STObject const ownerDir = createOwnerDirLedgerObject(
|
||||
{xrpl::uint256{kIssuanceIndeX1}, xrpl::uint256{kIssuanceIndeX2}}, kIssuanceIndeX1
|
||||
{xrpl::uint256{kIssuanceIndex1}, xrpl::uint256{kIssuanceIndex2}}, kIssuanceIndex1
|
||||
);
|
||||
EXPECT_CALL(*backend_, doFetchLedgerObject(ownerDirKk, _, _))
|
||||
.WillOnce(Return(ownerDir.getSerializer().peekData()));
|
||||
@@ -758,7 +765,7 @@ TEST_F(RPCAccountMPTokenIssuancesHandlerTest, LimitMoreThanMax)
|
||||
.WillOnce(Return(Blob{'f', 'a', 'k', 'e'}));
|
||||
|
||||
xrpl::STObject const ownerDir = createOwnerDirLedgerObject(
|
||||
{xrpl::uint256{kIssuanceIndeX1}, xrpl::uint256{kIssuanceIndeX2}}, kIssuanceIndeX1
|
||||
{xrpl::uint256{kIssuanceIndex1}, xrpl::uint256{kIssuanceIndex2}}, kIssuanceIndex1
|
||||
);
|
||||
EXPECT_CALL(*backend_, doFetchLedgerObject(ownerDirKk, _, _))
|
||||
.WillOnce(Return(ownerDir.getSerializer().peekData()));
|
||||
@@ -845,7 +852,7 @@ TEST_F(RPCAccountMPTokenIssuancesHandlerTest, EmptyResult)
|
||||
EXPECT_CALL(*backend_, doFetchLedgerObject(accountKk, _, _))
|
||||
.WillOnce(Return(Blob{'f', 'a', 'k', 'e'}));
|
||||
|
||||
xrpl::STObject const ownerDir = createOwnerDirLedgerObject({}, kIssuanceIndeX1);
|
||||
xrpl::STObject const ownerDir = createOwnerDirLedgerObject({}, kIssuanceIndex1);
|
||||
EXPECT_CALL(*backend_, doFetchLedgerObject(ownerDirKk, _, _))
|
||||
.WillOnce(Return(ownerDir.getSerializer().peekData()));
|
||||
|
||||
@@ -913,7 +920,7 @@ TEST_P(AccountMPTokenIssuancesAmountSerializationTest, SerializedAsStrings)
|
||||
.WillOnce(Return(Blob{'f', 'a', 'k', 'e'}));
|
||||
|
||||
xrpl::STObject const ownerDir =
|
||||
createOwnerDirLedgerObject({xrpl::uint256{kIssuanceIndeX1}}, kIssuanceIndeX1);
|
||||
createOwnerDirLedgerObject({xrpl::uint256{kIssuanceIndex1}}, kIssuanceIndex1);
|
||||
EXPECT_CALL(*backend_, doFetchLedgerObject(ownerDirKk, _, _))
|
||||
.WillOnce(Return(ownerDir.getSerializer().peekData()));
|
||||
|
||||
@@ -974,7 +981,7 @@ TEST_F(RPCAccountMPTokenIssuancesHandlerTest, ImmutableFlags)
|
||||
.WillOnce(Return(Blob{'f', 'a', 'k', 'e'}));
|
||||
|
||||
xrpl::STObject const ownerDir = createOwnerDirLedgerObject(
|
||||
{xrpl::uint256{kIssuanceIndeX1}, xrpl::uint256{kIssuanceIndeX2}}, kIssuanceIndeX1
|
||||
{xrpl::uint256{kIssuanceIndex1}, xrpl::uint256{kIssuanceIndex2}}, kIssuanceIndex1
|
||||
);
|
||||
EXPECT_CALL(*backend_, doFetchLedgerObject(ownerDirKk, _, _))
|
||||
.WillOnce(Return(ownerDir.getSerializer().peekData()));
|
||||
@@ -1062,11 +1069,11 @@ TEST_F(RPCAccountMPTokenIssuancesHandlerTest, ImmutableFlags)
|
||||
}})JSON",
|
||||
kAccount,
|
||||
kLedgerHash,
|
||||
kIssuanceIndeX1,
|
||||
expectedMptIssuanceId(3),
|
||||
kAccount,
|
||||
kIssuancE1OutstandingAmount,
|
||||
kIssuancE1TransferFee,
|
||||
kIssuanceIndeX2,
|
||||
expectedMptIssuanceId(5),
|
||||
kAccount,
|
||||
kIssuancE2OutstandingAmount,
|
||||
kIssuancE2TransferFee,
|
||||
@@ -1096,7 +1103,7 @@ TEST_F(RPCAccountMPTokenIssuancesHandlerTest, ConfidentialFields)
|
||||
.WillOnce(Return(Blob{'f', 'a', 'k', 'e'}));
|
||||
|
||||
xrpl::STObject const ownerDir =
|
||||
createOwnerDirLedgerObject({xrpl::uint256{kIssuanceIndeX1}}, kIssuanceIndeX1);
|
||||
createOwnerDirLedgerObject({xrpl::uint256{kIssuanceIndex1}}, kIssuanceIndex1);
|
||||
EXPECT_CALL(*backend_, doFetchLedgerObject(ownerDirKk, _, _))
|
||||
.WillOnce(Return(ownerDir.getSerializer().peekData()));
|
||||
|
||||
@@ -1151,7 +1158,7 @@ TEST_F(RPCAccountMPTokenIssuancesHandlerTest, ConfidentialFields)
|
||||
}})JSON",
|
||||
kAccount,
|
||||
kLedgerHash,
|
||||
kIssuanceIndeX1,
|
||||
expectedMptIssuanceId(1),
|
||||
kAccount,
|
||||
kIssuancE1OutstandingAmount,
|
||||
kConfidentialOutstandingAmount,
|
||||
@@ -1166,6 +1173,54 @@ TEST_F(RPCAccountMPTokenIssuancesHandlerTest, ConfidentialFields)
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(RPCAccountMPTokenIssuancesHandlerTest, MPTokenIssuanceIdIsDerivedIdNotLedgerKey)
|
||||
{
|
||||
constexpr std::uint32_t kSequence = 7;
|
||||
|
||||
auto const ledgerHeader = createLedgerHeader(kLedgerHash, 30);
|
||||
EXPECT_CALL(*backend_, fetchLedgerBySequence).WillOnce(Return(ledgerHeader));
|
||||
|
||||
auto const account = getAccountIdWithString(kAccount);
|
||||
auto const accountKk = xrpl::keylet::account(account).key;
|
||||
auto const ownerDirKk = xrpl::keylet::ownerDir(account).key;
|
||||
EXPECT_CALL(*backend_, doFetchLedgerObject(accountKk, _, _))
|
||||
.WillOnce(Return(Blob{'f', 'a', 'k', 'e'}));
|
||||
|
||||
xrpl::STObject const ownerDir =
|
||||
createOwnerDirLedgerObject({xrpl::uint256{kIssuanceIndex1}}, kIssuanceIndex1);
|
||||
EXPECT_CALL(*backend_, doFetchLedgerObject(ownerDirKk, _, _))
|
||||
.WillOnce(Return(ownerDir.getSerializer().peekData()));
|
||||
|
||||
auto const bbs =
|
||||
std::vector<Blob>{createMptIssuanceObject(kAccount, kSequence).getSerializer().peekData()};
|
||||
EXPECT_CALL(*backend_, doFetchLedgerObjects).WillOnce(Return(bbs));
|
||||
|
||||
runSpawn([this](auto yield) {
|
||||
auto const input =
|
||||
boost::json::parse(fmt::format(R"JSON({{"account": "{}"}})JSON", kAccount));
|
||||
auto const handler = AnyHandler{AccountMPTokenIssuancesHandler{this->backend_}};
|
||||
auto const output = handler.process(input, Context{yield});
|
||||
ASSERT_TRUE(output);
|
||||
|
||||
auto const& issuances = output.result->as_object().at("mpt_issuances").as_array();
|
||||
ASSERT_EQ(issuances.size(), 1);
|
||||
|
||||
auto const& issuance = issuances[0].as_object();
|
||||
ASSERT_TRUE(issuance.at("mpt_issuance_id").is_string());
|
||||
auto const mptIssuanceId = issuance.at("mpt_issuance_id").as_string();
|
||||
|
||||
EXPECT_EQ(mptIssuanceId.size(), 48);
|
||||
EXPECT_EQ(mptIssuanceId, expectedMptIssuanceId(kSequence));
|
||||
EXPECT_NE(mptIssuanceId, kIssuanceIndex1);
|
||||
|
||||
auto const asOuterObject = boost::json::value{{"mpt_issuance_id", mptIssuanceId}};
|
||||
auto const validated = validation::CustomValidators::uint192HexStringValidator.verify(
|
||||
asOuterObject, "mpt_issuance_id"
|
||||
);
|
||||
EXPECT_TRUE(validated.has_value());
|
||||
});
|
||||
}
|
||||
|
||||
struct SingleFlagTest {
|
||||
std::string testName;
|
||||
uint32_t flag;
|
||||
@@ -1218,7 +1273,7 @@ TEST_P(AccountMPTokenIssuancesLedgerFlagsTest, SingleFlag)
|
||||
.WillOnce(Return(Blob{'f', 'a', 'k', 'e'}));
|
||||
|
||||
xrpl::STObject const ownerDir =
|
||||
createOwnerDirLedgerObject({xrpl::uint256{kIssuanceIndeX1}}, kIssuanceIndeX1);
|
||||
createOwnerDirLedgerObject({xrpl::uint256{kIssuanceIndex1}}, kIssuanceIndex1);
|
||||
EXPECT_CALL(*backend_, doFetchLedgerObject(ownerDirKk, _, _))
|
||||
.WillOnce(Return(ownerDir.getSerializer().peekData()));
|
||||
|
||||
@@ -1316,7 +1371,7 @@ TEST_P(AccountMPTokenIssuancesImmutableFlagsTest, SingleImmutableFlag)
|
||||
.WillOnce(Return(Blob{'f', 'a', 'k', 'e'}));
|
||||
|
||||
xrpl::STObject const ownerDir =
|
||||
createOwnerDirLedgerObject({xrpl::uint256{kIssuanceIndeX1}}, kIssuanceIndeX1);
|
||||
createOwnerDirLedgerObject({xrpl::uint256{kIssuanceIndex1}}, kIssuanceIndex1);
|
||||
EXPECT_CALL(*backend_, doFetchLedgerObject(ownerDirKk, _, _))
|
||||
.WillOnce(Return(ownerDir.getSerializer().peekData()));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user