Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unify json #992

Merged
merged 5 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 28 additions & 13 deletions src/rpc/RPCHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,21 +295,26 @@ toJson(ripple::SLE const& sle)
}

boost::json::object
toJson(ripple::LedgerHeader const& lgrInfo)
toJson(ripple::LedgerHeader const& lgrInfo, bool const binary)
{
boost::json::object header;
header["ledger_sequence"] = lgrInfo.seq;
header["ledger_hash"] = ripple::strHex(lgrInfo.hash);
header["txns_hash"] = ripple::strHex(lgrInfo.txHash);
header["state_hash"] = ripple::strHex(lgrInfo.accountHash);
header["parent_hash"] = ripple::strHex(lgrInfo.parentHash);
header["total_coins"] = ripple::to_string(lgrInfo.drops);
header["close_flags"] = lgrInfo.closeFlags;

// Always show fields that contribute to the ledger hash
header["parent_close_time"] = lgrInfo.parentCloseTime.time_since_epoch().count();
header["close_time"] = lgrInfo.closeTime.time_since_epoch().count();
header["close_time_resolution"] = lgrInfo.closeTimeResolution.count();
if (binary) {
header[JS(ledger_data)] = ripple::strHex(ledgerInfoToBlob(lgrInfo));
} else {
header[JS(account_hash)] = ripple::strHex(lgrInfo.accountHash);
header[JS(close_flags)] = lgrInfo.closeFlags;
header[JS(close_time)] = lgrInfo.closeTime.time_since_epoch().count();
header[JS(close_time_human)] = ripple::to_string(lgrInfo.closeTime);
header[JS(close_time_resolution)] = lgrInfo.closeTimeResolution.count();
header[JS(close_time_iso)] = ripple::to_string_iso(lgrInfo.closeTime);
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_hash)] = ripple::strHex(lgrInfo.parentHash);
header[JS(total_coins)] = ripple::to_string(lgrInfo.drops);
header[JS(transaction_hash)] = ripple::strHex(lgrInfo.txHash);
}
header[JS(closed)] = true;
return header;
}

Expand Down Expand Up @@ -1308,4 +1313,14 @@ isAmendmentEnabled(
return std::find(listAmendments.begin(), listAmendments.end(), amendmentId) != listAmendments.end();
}

boost::json::object
toJsonWithBinaryTx(data::TransactionAndMetadata const& txnPlusMeta, std::uint32_t const apiVersion)
{
boost::json::object obj{};
auto const metaKey = apiVersion > 1 ? JS(meta_blob) : JS(meta);
obj[metaKey] = ripple::strHex(txnPlusMeta.metadata);
obj[JS(tx_blob)] = ripple::strHex(txnPlusMeta.transaction);
return obj;
}

} // namespace rpc
19 changes: 18 additions & 1 deletion src/rpc/RPCHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,16 @@ toExpandedJson(
std::optional<uint16_t> networkId = std::nullopt
);

/**
* @brief Convert a TransactionAndMetadata to JSON object containing tx and metadata data in hex format. According to
* the apiVersion, the key is "tx_blob" and "meta" or "meta_blob".
* @param txnPlusMeta The TransactionAndMetadata to convert.
* @param apiVersion The api version
* @return The JSON object containing tx and metadata data in hex format.
*/
boost::json::object
toJsonWithBinaryTx(data::TransactionAndMetadata const& txnPlusMeta, std::uint32_t apiVersion);

/**
* @brief Add "DeliverMax" which is the alias of "Amount" for "Payment" transaction to transaction json. Remove the
* "Amount" field when version is greater than 1
Expand All @@ -101,8 +111,15 @@ toJson(ripple::STBase const& obj);
boost::json::object
toJson(ripple::SLE const& sle);

/**
* @brief Convert a LedgerHeader to JSON object.
*
* @param entry The LedgerHeader to convert.
* @param binary Whether to convert in hex format.
* @return The JSON object.
*/
boost::json::object
toJson(ripple::LedgerHeader const& info);
toJson(ripple::LedgerHeader const& info, bool binary);

boost::json::object
toJson(ripple::TxMeta const& meta);
Expand Down
35 changes: 24 additions & 11 deletions src/rpc/handlers/AccountTx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,9 @@ AccountTxHandler::process(AccountTxHandler::Input input, Context const& ctx) con
boost::json::object obj;
if (!input.binary) {
auto [txn, meta] = toExpandedJson(txnPlusMeta, ctx.apiVersion, NFTokenjson::ENABLE);
obj[JS(meta)] = std::move(meta);
obj[JS(tx)] = std::move(txn);

if (obj[JS(tx)].as_object().contains(JS(TransactionType))) {
auto const objTransactionType = obj[JS(tx)].as_object()[JS(TransactionType)];
if (txn.contains(JS(TransactionType))) {
auto const objTransactionType = txn[JS(TransactionType)];
auto const strType = util::toLower(objTransactionType.as_string().c_str());

// if transactionType does not match
Expand All @@ -179,14 +177,29 @@ AccountTxHandler::process(AccountTxHandler::Input input, Context const& ctx) con
continue;
}

obj[JS(tx)].as_object()[JS(date)] = txnPlusMeta.date;
obj[JS(tx)].as_object()[JS(ledger_index)] = txnPlusMeta.ledgerSequence;

if (ctx.apiVersion < 2u)
obj[JS(tx)].as_object()[JS(inLedger)] = txnPlusMeta.ledgerSequence;
auto const txKey = ctx.apiVersion < 2u ? JS(tx) : JS(tx_json);
obj[JS(meta)] = std::move(meta);
obj[txKey] = std::move(txn);
obj[txKey].as_object()[JS(date)] = txnPlusMeta.date;
obj[txKey].as_object()[JS(ledger_index)] = txnPlusMeta.ledgerSequence;

if (ctx.apiVersion < 2u) {
obj[txKey].as_object()[JS(inLedger)] = txnPlusMeta.ledgerSequence;
} else {
obj[JS(ledger_index)] = txnPlusMeta.ledgerSequence;
if (obj[txKey].as_object().contains(JS(hash))) {
obj[JS(hash)] = obj[txKey].as_object()[JS(hash)];
obj[txKey].as_object().erase(JS(hash));
}
if (auto const ledgerInfo =
sharedPtrBackend_->fetchLedgerBySequence(txnPlusMeta.ledgerSequence, ctx.yield);
ledgerInfo) {
obj[JS(ledger_hash)] = ripple::strHex(ledgerInfo->hash);
obj[JS(close_time_iso)] = ripple::to_string_iso(ledgerInfo->closeTime);
}
}
} else {
obj[JS(meta)] = ripple::strHex(txnPlusMeta.metadata);
obj[JS(tx_blob)] = ripple::strHex(txnPlusMeta.transaction);
obj = toJsonWithBinaryTx(txnPlusMeta, ctx.apiVersion);
obj[JS(ledger_index)] = txnPlusMeta.ledgerSequence;
}

Expand Down
63 changes: 36 additions & 27 deletions src/rpc/handlers/Ledger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,7 @@ LedgerHandler::process(LedgerHandler::Input input, Context const& ctx) const
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
Output output;

if (input.binary) {
output.header[JS(ledger_data)] = ripple::strHex(ledgerInfoToBlob(lgrInfo));
} else {
output.header[JS(account_hash)] = ripple::strHex(lgrInfo.accountHash);
output.header[JS(close_flags)] = lgrInfo.closeFlags;
output.header[JS(close_time)] = lgrInfo.closeTime.time_since_epoch().count();
output.header[JS(close_time_human)] = ripple::to_string(lgrInfo.closeTime);
output.header[JS(close_time_resolution)] = lgrInfo.closeTimeResolution.count();
output.header[JS(closed)] = true;
output.header[JS(ledger_hash)] = ripple::strHex(lgrInfo.hash);
output.header[JS(ledger_index)] = std::to_string(lgrInfo.seq);
output.header[JS(parent_close_time)] = lgrInfo.parentCloseTime.time_since_epoch().count();
output.header[JS(parent_hash)] = ripple::strHex(lgrInfo.parentHash);
output.header[JS(total_coins)] = ripple::to_string(lgrInfo.drops);
output.header[JS(transaction_hash)] = ripple::strHex(lgrInfo.txHash);
}

output.header[JS(closed)] = true;
output.header = toJson(lgrInfo, input.binary);

if (input.transactions) {
output.header[JS(transactions)] = boost::json::value(boost::json::array_kind);
Expand All @@ -60,20 +43,46 @@ LedgerHandler::process(LedgerHandler::Input input, Context const& ctx) const
if (input.expand) {
auto txns = sharedPtrBackend_->fetchAllTransactionsInLedger(lgrInfo.seq, ctx.yield);

auto const expandTxJsonV1 = [&](data::TransactionAndMetadata const& tx) {
if (!input.binary) {
auto [txn, meta] = toExpandedJson(tx, ctx.apiVersion);
txn[JS(metaData)] = std::move(meta);
return txn;
}
return toJsonWithBinaryTx(tx, ctx.apiVersion);
};

auto const expandTxJsonV2 = [&](data::TransactionAndMetadata const& tx) {
static auto const isoTimeStr = ripple::to_string_iso(lgrInfo.closeTime);
auto [txn, meta] = toExpandedJson(tx, ctx.apiVersion);
if (!input.binary) {
boost::json::object entry;
entry[JS(validated)] = true;
// same with rippled, ledger_index is a string here
entry[JS(ledger_index)] = std::to_string(lgrInfo.seq);
entry[JS(close_time_iso)] = isoTimeStr;
entry[JS(ledger_hash)] = ripple::strHex(lgrInfo.hash);
if (txn.contains(JS(hash))) {
entry[JS(hash)] = txn.at(JS(hash));
txn.erase(JS(hash));
}
entry[JS(tx_json)] = std::move(txn);
entry[JS(meta)] = std::move(meta);
return entry;
}

auto entry = toJsonWithBinaryTx(tx, ctx.apiVersion);
if (txn.contains(JS(hash)))
entry[JS(hash)] = txn.at(JS(hash));
return entry;
};

std::transform(
std::move_iterator(txns.begin()),
std::move_iterator(txns.end()),
std::back_inserter(jsonTxs),
[&](auto obj) {
boost::json::object entry;
if (!input.binary) {
auto [txn, meta] = toExpandedJson(obj, ctx.apiVersion);
entry = std::move(txn);
entry[JS(metaData)] = std::move(meta);
} else {
entry[JS(tx_blob)] = ripple::strHex(obj.transaction);
entry[JS(meta)] = ripple::strHex(obj.metadata);
}
boost::json::object entry = ctx.apiVersion < 2u ? expandTxJsonV1(obj) : expandTxJsonV2(obj);

if (input.ownerFunds) {
// check the type of tx
Expand Down
22 changes: 2 additions & 20 deletions src/rpc/handlers/LedgerData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,29 +73,11 @@ LedgerDataHandler::process(Input input, Context const& ctx) const

auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);

// no marker -> first call, return header information
auto header = boost::json::object();
Output output;

// no marker -> first call, return header information
if ((!input.marker) && (!input.diffMarker)) {
if (input.binary) {
header[JS(ledger_data)] = ripple::strHex(ledgerInfoToBlob(lgrInfo));
} else {
header[JS(account_hash)] = ripple::strHex(lgrInfo.accountHash);
header[JS(close_flags)] = lgrInfo.closeFlags;
header[JS(close_time)] = lgrInfo.closeTime.time_since_epoch().count();
header[JS(close_time_human)] = ripple::to_string(lgrInfo.closeTime);
header[JS(close_time_resolution)] = lgrInfo.closeTimeResolution.count();
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_hash)] = ripple::strHex(lgrInfo.parentHash);
header[JS(total_coins)] = ripple::to_string(lgrInfo.drops);
header[JS(transaction_hash)] = ripple::strHex(lgrInfo.txHash);
}

header[JS(closed)] = true;
output.header = std::move(header);
output.header = toJson(lgrInfo, input.binary);
} else {
if (input.marker && !sharedPtrBackend_->fetchLedgerObject(*(input.marker), lgrInfo.seq, ctx.yield))
return Error{Status{RippledError::rpcINVALID_PARAMS, "markerDoesNotExist"}};
Expand Down
24 changes: 18 additions & 6 deletions src/rpc/handlers/NFTHistory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,27 @@ NFTHistoryHandler::process(NFTHistoryHandler::Input input, Context const& ctx) c

if (!input.binary) {
auto [txn, meta] = toExpandedJson(txnPlusMeta, ctx.apiVersion);
auto const txKey = ctx.apiVersion > 1u ? JS(tx_json) : JS(tx);
obj[JS(meta)] = std::move(meta);
obj[JS(tx)] = std::move(txn);
obj[JS(tx)].as_object()[JS(ledger_index)] = txnPlusMeta.ledgerSequence;
obj[JS(tx)].as_object()[JS(date)] = txnPlusMeta.date;
obj[txKey] = std::move(txn);
obj[txKey].as_object()[JS(ledger_index)] = txnPlusMeta.ledgerSequence;
obj[txKey].as_object()[JS(date)] = txnPlusMeta.date;
if (ctx.apiVersion > 1u) {
obj[JS(ledger_index)] = txnPlusMeta.ledgerSequence;
if (obj[txKey].as_object().contains(JS(hash))) {
obj[JS(hash)] = obj[txKey].at(JS(hash));
obj[txKey].as_object().erase(JS(hash));
}
if (auto const lgrInfo =
sharedPtrBackend_->fetchLedgerBySequence(txnPlusMeta.ledgerSequence, ctx.yield);
lgrInfo) {
obj[JS(close_time_iso)] = ripple::to_string_iso(lgrInfo->closeTime);
obj[JS(ledger_hash)] = ripple::strHex(lgrInfo->hash);
}
}
} else {
obj[JS(meta)] = ripple::strHex(txnPlusMeta.metadata);
obj[JS(tx_blob)] = ripple::strHex(txnPlusMeta.transaction);
obj = toJsonWithBinaryTx(txnPlusMeta, ctx.apiVersion);
obj[JS(ledger_index)] = txnPlusMeta.ledgerSequence;
// only clio has this field
obj[JS(date)] = txnPlusMeta.date;
}

Expand Down
25 changes: 17 additions & 8 deletions src/rpc/handlers/TransactionEntry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ TransactionEntryHandler::process(TransactionEntryHandler::Input input, Context c
if (auto status = std::get_if<Status>(&lgrInfoOrStatus))
return Error{*status};

auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
auto output = TransactionEntryHandler::Output{};
output.apiVersion = ctx.apiVersion;

output.ledgerHeader = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
auto const dbRet = sharedPtrBackend_->fetchTransaction(ripple::uint256{input.txHash.c_str()}, ctx.yield);
// Note: transaction_entry is meant to only search a specified ledger for
// the specified transaction. tx searches the entire range of history. For
Expand All @@ -43,30 +46,36 @@ TransactionEntryHandler::process(TransactionEntryHandler::Input input, Context c
// the API for transaction_entry says the method only searches the specified
// ledger; we simulate that here by returning not found if the transaction
// is in a different ledger than the one specified.
if (!dbRet || dbRet->ledgerSequence != lgrInfo.seq)
if (!dbRet || dbRet->ledgerSequence != output.ledgerHeader->seq)
return Error{Status{RippledError::rpcTXN_NOT_FOUND, "transactionNotFound", "Transaction not found."}};

auto output = TransactionEntryHandler::Output{};
auto [txn, meta] = toExpandedJson(*dbRet, ctx.apiVersion);

output.tx = std::move(txn);
output.metadata = std::move(meta);
output.ledgerIndex = lgrInfo.seq;
output.ledgerHash = ripple::strHex(lgrInfo.hash);

return output;
}

void
tag_invoke(boost::json::value_from_tag, boost::json::value& jv, TransactionEntryHandler::Output const& output)
{
auto const metaKey = output.apiVersion > 1u ? JS(meta) : JS(metadata);
jv = {
{JS(validated), output.validated},
{JS(metadata), output.metadata},
{metaKey, output.metadata},
{JS(tx_json), output.tx},
{JS(ledger_index), output.ledgerIndex},
{JS(ledger_hash), output.ledgerHash},
{JS(ledger_index), output.ledgerHeader->seq},
{JS(ledger_hash), ripple::strHex(output.ledgerHeader->hash)},
};

if (output.apiVersion > 1u) {
jv.as_object()[JS(close_time_iso)] = ripple::to_string_iso(output.ledgerHeader->closeTime);
if (output.tx.contains(JS(hash))) {
jv.as_object()[JS(hash)] = output.tx.at(JS(hash));
jv.as_object()[JS(tx_json)].as_object().erase(JS(hash));
}
}
}

TransactionEntryHandler::Input
Expand Down
4 changes: 2 additions & 2 deletions src/rpc/handlers/TransactionEntry.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ class TransactionEntryHandler {

public:
struct Output {
uint32_t ledgerIndex;
std::string ledgerHash;
std::optional<ripple::LedgerHeader> ledgerHeader;
// TODO: use a better type for this
boost::json::object metadata;
boost::json::object tx;
// validated should be sent via framework
bool validated = true;
uint32_t apiVersion;
};

struct Input {
Expand Down
Loading