mirror of
https://github.com/XRPLF/clio.git
synced 2025-11-21 20:25:52 +00:00
@@ -359,7 +359,7 @@ toJson(ripple::SLE const& sle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
boost::json::object
|
boost::json::object
|
||||||
toJson(ripple::LedgerHeader const& lgrInfo, bool const binary)
|
toJson(ripple::LedgerHeader const& lgrInfo, bool const binary, std::uint32_t const apiVersion)
|
||||||
{
|
{
|
||||||
boost::json::object header;
|
boost::json::object header;
|
||||||
if (binary) {
|
if (binary) {
|
||||||
@@ -372,11 +372,16 @@ toJson(ripple::LedgerHeader const& lgrInfo, bool const binary)
|
|||||||
header[JS(close_time_resolution)] = lgrInfo.closeTimeResolution.count();
|
header[JS(close_time_resolution)] = lgrInfo.closeTimeResolution.count();
|
||||||
header[JS(close_time_iso)] = ripple::to_string_iso(lgrInfo.closeTime);
|
header[JS(close_time_iso)] = ripple::to_string_iso(lgrInfo.closeTime);
|
||||||
header[JS(ledger_hash)] = ripple::strHex(lgrInfo.hash);
|
header[JS(ledger_hash)] = ripple::strHex(lgrInfo.hash);
|
||||||
header[JS(ledger_index)] = std::to_string(lgrInfo.seq);
|
|
||||||
header[JS(parent_close_time)] = lgrInfo.parentCloseTime.time_since_epoch().count();
|
header[JS(parent_close_time)] = lgrInfo.parentCloseTime.time_since_epoch().count();
|
||||||
header[JS(parent_hash)] = ripple::strHex(lgrInfo.parentHash);
|
header[JS(parent_hash)] = ripple::strHex(lgrInfo.parentHash);
|
||||||
header[JS(total_coins)] = ripple::to_string(lgrInfo.drops);
|
header[JS(total_coins)] = ripple::to_string(lgrInfo.drops);
|
||||||
header[JS(transaction_hash)] = ripple::strHex(lgrInfo.txHash);
|
header[JS(transaction_hash)] = ripple::strHex(lgrInfo.txHash);
|
||||||
|
|
||||||
|
if (apiVersion < 2u) {
|
||||||
|
header[JS(ledger_index)] = std::to_string(lgrInfo.seq);
|
||||||
|
} else {
|
||||||
|
header[JS(ledger_index)] = lgrInfo.seq;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
header[JS(closed)] = true;
|
header[JS(closed)] = true;
|
||||||
return header;
|
return header;
|
||||||
|
|||||||
@@ -115,10 +115,11 @@ toJson(ripple::SLE const& sle);
|
|||||||
*
|
*
|
||||||
* @param entry The LedgerHeader to convert.
|
* @param entry The LedgerHeader to convert.
|
||||||
* @param binary Whether to convert in hex format.
|
* @param binary Whether to convert in hex format.
|
||||||
|
* @param apiVersion The api version
|
||||||
* @return The JSON object.
|
* @return The JSON object.
|
||||||
*/
|
*/
|
||||||
boost::json::object
|
boost::json::object
|
||||||
toJson(ripple::LedgerHeader const& info, bool binary);
|
toJson(ripple::LedgerHeader const& info, bool binary, std::uint32_t apiVersion);
|
||||||
|
|
||||||
boost::json::object
|
boost::json::object
|
||||||
toJson(ripple::TxMeta const& meta);
|
toJson(ripple::TxMeta const& meta);
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ LedgerHandler::process(LedgerHandler::Input input, Context const& ctx) const
|
|||||||
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
|
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
|
||||||
Output output;
|
Output output;
|
||||||
|
|
||||||
output.header = toJson(lgrInfo, input.binary);
|
output.header = toJson(lgrInfo, input.binary, ctx.apiVersion);
|
||||||
|
|
||||||
if (input.transactions) {
|
if (input.transactions) {
|
||||||
output.header[JS(transactions)] = boost::json::value(boost::json::array_kind);
|
output.header[JS(transactions)] = boost::json::value(boost::json::array_kind);
|
||||||
@@ -86,8 +86,13 @@ LedgerHandler::process(LedgerHandler::Input input, Context const& ctx) const
|
|||||||
if (!input.binary) {
|
if (!input.binary) {
|
||||||
boost::json::object entry;
|
boost::json::object entry;
|
||||||
entry[JS(validated)] = true;
|
entry[JS(validated)] = true;
|
||||||
// same with rippled, ledger_index is a string here
|
|
||||||
|
if (ctx.apiVersion < 2u) {
|
||||||
entry[JS(ledger_index)] = std::to_string(lgrInfo.seq);
|
entry[JS(ledger_index)] = std::to_string(lgrInfo.seq);
|
||||||
|
} else {
|
||||||
|
entry[JS(ledger_index)] = lgrInfo.seq;
|
||||||
|
}
|
||||||
|
|
||||||
entry[JS(close_time_iso)] = isoTimeStr;
|
entry[JS(close_time_iso)] = isoTimeStr;
|
||||||
entry[JS(ledger_hash)] = ripple::strHex(lgrInfo.hash);
|
entry[JS(ledger_hash)] = ripple::strHex(lgrInfo.hash);
|
||||||
if (txn.contains(JS(hash))) {
|
if (txn.contains(JS(hash))) {
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ LedgerDataHandler::process(Input input, Context const& ctx) const
|
|||||||
|
|
||||||
// no marker -> first call, return header information
|
// no marker -> first call, return header information
|
||||||
if ((!input.marker) && (!input.diffMarker)) {
|
if ((!input.marker) && (!input.diffMarker)) {
|
||||||
output.header = toJson(lgrInfo, input.binary);
|
output.header = toJson(lgrInfo, input.binary, ctx.apiVersion);
|
||||||
} else {
|
} else {
|
||||||
if (input.marker && !sharedPtrBackend_->fetchLedgerObject(*(input.marker), lgrInfo.seq, ctx.yield))
|
if (input.marker && !sharedPtrBackend_->fetchLedgerObject(*(input.marker), lgrInfo.seq, ctx.yield))
|
||||||
return Error{Status{RippledError::rpcINVALID_PARAMS, "markerDoesNotExist"}};
|
return Error{Status{RippledError::rpcINVALID_PARAMS, "markerDoesNotExist"}};
|
||||||
|
|||||||
@@ -443,7 +443,7 @@ TEST_F(RPCHelpersTest, DeliverMaxAliasV2)
|
|||||||
TEST_F(RPCHelpersTest, LedgerHeaderJson)
|
TEST_F(RPCHelpersTest, LedgerHeaderJson)
|
||||||
{
|
{
|
||||||
auto const ledgerHeader = CreateLedgerInfo(INDEX1, 30);
|
auto const ledgerHeader = CreateLedgerInfo(INDEX1, 30);
|
||||||
auto const binJson = toJson(ledgerHeader, true);
|
auto const binJson = toJson(ledgerHeader, true, 1u);
|
||||||
|
|
||||||
auto constexpr EXPECTBIN = R"({
|
auto constexpr EXPECTBIN = R"({
|
||||||
"ledger_data": "0000001E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
"ledger_data": "0000001E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
@@ -469,7 +469,35 @@ TEST_F(RPCHelpersTest, LedgerHeaderJson)
|
|||||||
INDEX1,
|
INDEX1,
|
||||||
30
|
30
|
||||||
);
|
);
|
||||||
auto json = toJson(ledgerHeader, false);
|
auto json = toJson(ledgerHeader, false, 1u);
|
||||||
|
// remove platform-related close_time_human field
|
||||||
|
json.erase(JS(close_time_human));
|
||||||
|
EXPECT_EQ(json, boost::json::parse(EXPECTJSON));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCHelpersTest, LedgerHeaderJsonV2)
|
||||||
|
{
|
||||||
|
auto const ledgerHeader = CreateLedgerInfo(INDEX1, 30);
|
||||||
|
|
||||||
|
auto const EXPECTJSON = fmt::format(
|
||||||
|
R"({{
|
||||||
|
"account_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"close_flags": 0,
|
||||||
|
"close_time": 0,
|
||||||
|
"close_time_resolution": 0,
|
||||||
|
"close_time_iso": "2000-01-01T00:00:00Z",
|
||||||
|
"ledger_hash": "{}",
|
||||||
|
"ledger_index": {},
|
||||||
|
"parent_close_time": 0,
|
||||||
|
"parent_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"total_coins": "0",
|
||||||
|
"transaction_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"closed": true
|
||||||
|
}})",
|
||||||
|
INDEX1,
|
||||||
|
30
|
||||||
|
);
|
||||||
|
auto json = toJson(ledgerHeader, false, 2u);
|
||||||
// remove platform-related close_time_human field
|
// remove platform-related close_time_human field
|
||||||
json.erase(JS(close_time_human));
|
json.erase(JS(close_time_human));
|
||||||
EXPECT_EQ(json, boost::json::parse(EXPECTJSON));
|
EXPECT_EQ(json, boost::json::parse(EXPECTJSON));
|
||||||
|
|||||||
@@ -262,9 +262,7 @@ TEST_F(RPCLedgerDataHandlerTest, NoMarker)
|
|||||||
mockBackendPtr->updateRange(RANGEMIN); // min
|
mockBackendPtr->updateRange(RANGEMIN); // min
|
||||||
mockBackendPtr->updateRange(RANGEMAX); // max
|
mockBackendPtr->updateRange(RANGEMAX); // max
|
||||||
|
|
||||||
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1);
|
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX)));
|
||||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _))
|
|
||||||
.WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX)));
|
|
||||||
|
|
||||||
// when 'type' not specified, default to all the types
|
// when 'type' not specified, default to all the types
|
||||||
auto limitLine = 5;
|
auto limitLine = 5;
|
||||||
@@ -284,8 +282,7 @@ TEST_F(RPCLedgerDataHandlerTest, NoMarker)
|
|||||||
bbs.push_back(ticket.getSerializer().peekData());
|
bbs.push_back(ticket.getSerializer().peekData());
|
||||||
}
|
}
|
||||||
|
|
||||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs));
|
||||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
|
||||||
|
|
||||||
runSpawn([&, this](auto yield) {
|
runSpawn([&, this](auto yield) {
|
||||||
auto const handler = AnyHandler{LedgerDataHandler{mockBackendPtr}};
|
auto const handler = AnyHandler{LedgerDataHandler{mockBackendPtr}};
|
||||||
@@ -293,7 +290,9 @@ TEST_F(RPCLedgerDataHandlerTest, NoMarker)
|
|||||||
auto output = handler.process(req, Context{yield});
|
auto output = handler.process(req, Context{yield});
|
||||||
ASSERT_TRUE(output);
|
ASSERT_TRUE(output);
|
||||||
EXPECT_TRUE(output->as_object().contains("ledger"));
|
EXPECT_TRUE(output->as_object().contains("ledger"));
|
||||||
//"close_time_human" 's format depends on platform, might be sightly different
|
|
||||||
|
// Note: the format of "close_time_human" depends on the platform and might differ per platform. It is however
|
||||||
|
// guaranteed to be consistent on the same platform.
|
||||||
EXPECT_EQ(output->as_object().at("ledger").as_object().erase("close_time_human"), 1);
|
EXPECT_EQ(output->as_object().at("ledger").as_object().erase("close_time_human"), 1);
|
||||||
EXPECT_EQ(output->as_object().at("ledger"), json::parse(ledgerExpected));
|
EXPECT_EQ(output->as_object().at("ledger"), json::parse(ledgerExpected));
|
||||||
EXPECT_EQ(output->as_object().at("marker").as_string(), INDEX2);
|
EXPECT_EQ(output->as_object().at("marker").as_string(), INDEX2);
|
||||||
@@ -303,6 +302,64 @@ TEST_F(RPCLedgerDataHandlerTest, NoMarker)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCLedgerDataHandlerTest, Version2)
|
||||||
|
{
|
||||||
|
static auto const ledgerExpected = R"({
|
||||||
|
"account_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"close_flags": 0,
|
||||||
|
"close_time": 0,
|
||||||
|
"close_time_resolution": 0,
|
||||||
|
"close_time_iso": "2000-01-01T00:00:00Z",
|
||||||
|
"ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
||||||
|
"ledger_index": 30,
|
||||||
|
"parent_close_time": 0,
|
||||||
|
"parent_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"total_coins": "0",
|
||||||
|
"transaction_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"closed": true
|
||||||
|
})";
|
||||||
|
|
||||||
|
auto const rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
|
||||||
|
ASSERT_NE(rawBackendPtr, nullptr);
|
||||||
|
mockBackendPtr->updateRange(RANGEMIN); // min
|
||||||
|
mockBackendPtr->updateRange(RANGEMAX); // max
|
||||||
|
|
||||||
|
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX)));
|
||||||
|
|
||||||
|
// When 'type' not specified, default to all the types
|
||||||
|
auto limitLine = 5;
|
||||||
|
auto limitTicket = 5;
|
||||||
|
|
||||||
|
std::vector<Blob> bbs;
|
||||||
|
EXPECT_CALL(*rawBackendPtr, doFetchSuccessorKey).Times(limitLine + limitTicket);
|
||||||
|
ON_CALL(*rawBackendPtr, doFetchSuccessorKey(_, RANGEMAX, _)).WillByDefault(Return(ripple::uint256{INDEX2}));
|
||||||
|
|
||||||
|
while ((limitLine--) != 0) {
|
||||||
|
auto const line = CreateRippleStateLedgerObject("USD", ACCOUNT2, 10, ACCOUNT, 100, ACCOUNT2, 200, TXNID, 123);
|
||||||
|
bbs.push_back(line.getSerializer().peekData());
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((limitTicket--) != 0) {
|
||||||
|
auto const ticket = CreateTicketLedgerObject(ACCOUNT, limitTicket);
|
||||||
|
bbs.push_back(ticket.getSerializer().peekData());
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs));
|
||||||
|
|
||||||
|
runSpawn([&, this](auto yield) {
|
||||||
|
auto const handler = AnyHandler{LedgerDataHandler{mockBackendPtr}};
|
||||||
|
auto const req = json::parse(R"({"limit":10})");
|
||||||
|
auto output = handler.process(req, Context{.yield = yield, .apiVersion = 2});
|
||||||
|
ASSERT_TRUE(output);
|
||||||
|
EXPECT_TRUE(output->as_object().contains("ledger"));
|
||||||
|
|
||||||
|
// Note: the format of "close_time_human" depends on the platform and might differ per platform. It is however
|
||||||
|
// guaranteed to be consistent on the same platform.
|
||||||
|
EXPECT_EQ(output->as_object().at("ledger").as_object().erase("close_time_human"), 1);
|
||||||
|
EXPECT_EQ(output->as_object().at("ledger"), json::parse(ledgerExpected));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(RPCLedgerDataHandlerTest, TypeFilter)
|
TEST_F(RPCLedgerDataHandlerTest, TypeFilter)
|
||||||
{
|
{
|
||||||
static auto const ledgerExpected = R"({
|
static auto const ledgerExpected = R"({
|
||||||
@@ -359,7 +416,9 @@ TEST_F(RPCLedgerDataHandlerTest, TypeFilter)
|
|||||||
auto output = handler.process(req, Context{yield});
|
auto output = handler.process(req, Context{yield});
|
||||||
ASSERT_TRUE(output);
|
ASSERT_TRUE(output);
|
||||||
EXPECT_TRUE(output->as_object().contains("ledger"));
|
EXPECT_TRUE(output->as_object().contains("ledger"));
|
||||||
//"close_time_human" 's format depends on platform, might be sightly different
|
|
||||||
|
// Note: the format of "close_time_human" depends on the platform and might differ per platform. It is however
|
||||||
|
// guaranteed to be consistent on the same platform.
|
||||||
EXPECT_EQ(output->as_object().at("ledger").as_object().erase("close_time_human"), 1);
|
EXPECT_EQ(output->as_object().at("ledger").as_object().erase("close_time_human"), 1);
|
||||||
EXPECT_EQ(output->as_object().at("ledger"), json::parse(ledgerExpected));
|
EXPECT_EQ(output->as_object().at("ledger"), json::parse(ledgerExpected));
|
||||||
EXPECT_EQ(output->as_object().at("marker").as_string(), INDEX2);
|
EXPECT_EQ(output->as_object().at("marker").as_string(), INDEX2);
|
||||||
@@ -422,7 +481,9 @@ TEST_F(RPCLedgerDataHandlerTest, TypeFilterAMM)
|
|||||||
auto output = handler.process(req, Context{yield});
|
auto output = handler.process(req, Context{yield});
|
||||||
ASSERT_TRUE(output);
|
ASSERT_TRUE(output);
|
||||||
EXPECT_TRUE(output->as_object().contains("ledger"));
|
EXPECT_TRUE(output->as_object().contains("ledger"));
|
||||||
//"close_time_human" 's format depends on platform, might be sightly different
|
|
||||||
|
// Note: the format of "close_time_human" depends on the platform and might differ per platform. It is however
|
||||||
|
// guaranteed to be consistent on the same platform.
|
||||||
EXPECT_EQ(output->as_object().at("ledger").as_object().erase("close_time_human"), 1);
|
EXPECT_EQ(output->as_object().at("ledger").as_object().erase("close_time_human"), 1);
|
||||||
EXPECT_EQ(output->as_object().at("ledger"), json::parse(ledgerExpected));
|
EXPECT_EQ(output->as_object().at("ledger"), json::parse(ledgerExpected));
|
||||||
EXPECT_EQ(output->as_object().at("marker").as_string(), INDEX2);
|
EXPECT_EQ(output->as_object().at("marker").as_string(), INDEX2);
|
||||||
|
|||||||
@@ -623,7 +623,7 @@ TEST_F(RPCLedgerHandlerTest, TransactionsExpandNotBinaryV2)
|
|||||||
"close_time_resolution": 0,
|
"close_time_resolution": 0,
|
||||||
"closed": true,
|
"closed": true,
|
||||||
"ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
"ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
||||||
"ledger_index": "30",
|
"ledger_index": 30,
|
||||||
"parent_close_time": 0,
|
"parent_close_time": 0,
|
||||||
"close_time_iso": "2000-01-01T00:00:00Z",
|
"close_time_iso": "2000-01-01T00:00:00Z",
|
||||||
"parent_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
"parent_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
@@ -635,7 +635,7 @@ TEST_F(RPCLedgerHandlerTest, TransactionsExpandNotBinaryV2)
|
|||||||
"close_time_iso": "2000-01-01T00:00:00Z",
|
"close_time_iso": "2000-01-01T00:00:00Z",
|
||||||
"hash": "70436A9332F7CD928FAEC1A41269A677739D8B11F108CE23AE23CBF0C9113F8C",
|
"hash": "70436A9332F7CD928FAEC1A41269A677739D8B11F108CE23AE23CBF0C9113F8C",
|
||||||
"ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
"ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
||||||
"ledger_index": "30",
|
"ledger_index": 30,
|
||||||
"tx_json":
|
"tx_json":
|
||||||
{
|
{
|
||||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
|
|||||||
Reference in New Issue
Block a user