mirror of
https://github.com/XRPLF/clio.git
synced 2025-11-26 14:45:52 +00:00
@@ -295,21 +295,26 @@ toJson(ripple::SLE const& sle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
boost::json::object
|
boost::json::object
|
||||||
toJson(ripple::LedgerHeader const& lgrInfo)
|
toJson(ripple::LedgerHeader const& lgrInfo, bool const binary)
|
||||||
{
|
{
|
||||||
boost::json::object header;
|
boost::json::object header;
|
||||||
header["ledger_sequence"] = lgrInfo.seq;
|
if (binary) {
|
||||||
header["ledger_hash"] = ripple::strHex(lgrInfo.hash);
|
header[JS(ledger_data)] = ripple::strHex(ledgerInfoToBlob(lgrInfo));
|
||||||
header["txns_hash"] = ripple::strHex(lgrInfo.txHash);
|
} else {
|
||||||
header["state_hash"] = ripple::strHex(lgrInfo.accountHash);
|
header[JS(account_hash)] = ripple::strHex(lgrInfo.accountHash);
|
||||||
header["parent_hash"] = ripple::strHex(lgrInfo.parentHash);
|
header[JS(close_flags)] = lgrInfo.closeFlags;
|
||||||
header["total_coins"] = ripple::to_string(lgrInfo.drops);
|
header[JS(close_time)] = lgrInfo.closeTime.time_since_epoch().count();
|
||||||
header["close_flags"] = lgrInfo.closeFlags;
|
header[JS(close_time_human)] = ripple::to_string(lgrInfo.closeTime);
|
||||||
|
header[JS(close_time_resolution)] = lgrInfo.closeTimeResolution.count();
|
||||||
// Always show fields that contribute to the ledger hash
|
header[JS(close_time_iso)] = ripple::to_string_iso(lgrInfo.closeTime);
|
||||||
header["parent_close_time"] = lgrInfo.parentCloseTime.time_since_epoch().count();
|
header[JS(ledger_hash)] = ripple::strHex(lgrInfo.hash);
|
||||||
header["close_time"] = lgrInfo.closeTime.time_since_epoch().count();
|
header[JS(ledger_index)] = std::to_string(lgrInfo.seq);
|
||||||
header["close_time_resolution"] = lgrInfo.closeTimeResolution.count();
|
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;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1308,4 +1313,14 @@ isAmendmentEnabled(
|
|||||||
return std::find(listAmendments.begin(), listAmendments.end(), amendmentId) != listAmendments.end();
|
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
|
} // namespace rpc
|
||||||
|
|||||||
@@ -78,6 +78,16 @@ toExpandedJson(
|
|||||||
std::optional<uint16_t> networkId = std::nullopt
|
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
|
* @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
|
* "Amount" field when version is greater than 1
|
||||||
@@ -101,8 +111,15 @@ toJson(ripple::STBase const& obj);
|
|||||||
boost::json::object
|
boost::json::object
|
||||||
toJson(ripple::SLE const& sle);
|
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
|
boost::json::object
|
||||||
toJson(ripple::LedgerHeader const& info);
|
toJson(ripple::LedgerHeader const& info, bool binary);
|
||||||
|
|
||||||
boost::json::object
|
boost::json::object
|
||||||
toJson(ripple::TxMeta const& meta);
|
toJson(ripple::TxMeta const& meta);
|
||||||
|
|||||||
@@ -166,11 +166,9 @@ AccountTxHandler::process(AccountTxHandler::Input input, Context const& ctx) con
|
|||||||
boost::json::object obj;
|
boost::json::object obj;
|
||||||
if (!input.binary) {
|
if (!input.binary) {
|
||||||
auto [txn, meta] = toExpandedJson(txnPlusMeta, ctx.apiVersion, NFTokenjson::ENABLE);
|
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))) {
|
if (txn.contains(JS(TransactionType))) {
|
||||||
auto const objTransactionType = obj[JS(tx)].as_object()[JS(TransactionType)];
|
auto const objTransactionType = txn[JS(TransactionType)];
|
||||||
auto const strType = util::toLower(objTransactionType.as_string().c_str());
|
auto const strType = util::toLower(objTransactionType.as_string().c_str());
|
||||||
|
|
||||||
// if transactionType does not match
|
// if transactionType does not match
|
||||||
@@ -179,14 +177,29 @@ AccountTxHandler::process(AccountTxHandler::Input input, Context const& ctx) con
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
obj[JS(tx)].as_object()[JS(date)] = txnPlusMeta.date;
|
auto const txKey = ctx.apiVersion < 2u ? JS(tx) : JS(tx_json);
|
||||||
obj[JS(tx)].as_object()[JS(ledger_index)] = txnPlusMeta.ledgerSequence;
|
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)
|
if (ctx.apiVersion < 2u) {
|
||||||
obj[JS(tx)].as_object()[JS(inLedger)] = txnPlusMeta.ledgerSequence;
|
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 {
|
} else {
|
||||||
obj[JS(meta)] = ripple::strHex(txnPlusMeta.metadata);
|
obj = toJsonWithBinaryTx(txnPlusMeta, ctx.apiVersion);
|
||||||
obj[JS(tx_blob)] = ripple::strHex(txnPlusMeta.transaction);
|
|
||||||
obj[JS(ledger_index)] = txnPlusMeta.ledgerSequence;
|
obj[JS(ledger_index)] = txnPlusMeta.ledgerSequence;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,24 +34,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;
|
||||||
|
|
||||||
if (input.binary) {
|
output.header = toJson(lgrInfo, 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;
|
|
||||||
|
|
||||||
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);
|
||||||
@@ -60,20 +43,46 @@ LedgerHandler::process(LedgerHandler::Input input, Context const& ctx) const
|
|||||||
if (input.expand) {
|
if (input.expand) {
|
||||||
auto txns = sharedPtrBackend_->fetchAllTransactionsInLedger(lgrInfo.seq, ctx.yield);
|
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::transform(
|
||||||
std::move_iterator(txns.begin()),
|
std::move_iterator(txns.begin()),
|
||||||
std::move_iterator(txns.end()),
|
std::move_iterator(txns.end()),
|
||||||
std::back_inserter(jsonTxs),
|
std::back_inserter(jsonTxs),
|
||||||
[&](auto obj) {
|
[&](auto obj) {
|
||||||
boost::json::object entry;
|
boost::json::object entry = ctx.apiVersion < 2u ? expandTxJsonV1(obj) : expandTxJsonV2(obj);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input.ownerFunds) {
|
if (input.ownerFunds) {
|
||||||
// check the type of tx
|
// check the type of tx
|
||||||
|
|||||||
@@ -73,29 +73,11 @@ LedgerDataHandler::process(Input input, Context const& ctx) const
|
|||||||
|
|
||||||
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
|
auto const lgrInfo = std::get<ripple::LedgerHeader>(lgrInfoOrStatus);
|
||||||
|
|
||||||
// no marker -> first call, return header information
|
|
||||||
auto header = boost::json::object();
|
|
||||||
Output output;
|
Output output;
|
||||||
|
|
||||||
|
// no marker -> first call, return header information
|
||||||
if ((!input.marker) && (!input.diffMarker)) {
|
if ((!input.marker) && (!input.diffMarker)) {
|
||||||
if (input.binary) {
|
output.header = toJson(lgrInfo, 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);
|
|
||||||
} 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"}};
|
||||||
|
|||||||
@@ -107,15 +107,27 @@ NFTHistoryHandler::process(NFTHistoryHandler::Input input, Context const& ctx) c
|
|||||||
|
|
||||||
if (!input.binary) {
|
if (!input.binary) {
|
||||||
auto [txn, meta] = toExpandedJson(txnPlusMeta, ctx.apiVersion);
|
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(meta)] = std::move(meta);
|
||||||
obj[JS(tx)] = std::move(txn);
|
obj[txKey] = std::move(txn);
|
||||||
obj[JS(tx)].as_object()[JS(ledger_index)] = txnPlusMeta.ledgerSequence;
|
obj[txKey].as_object()[JS(ledger_index)] = txnPlusMeta.ledgerSequence;
|
||||||
obj[JS(tx)].as_object()[JS(date)] = txnPlusMeta.date;
|
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 {
|
} else {
|
||||||
obj[JS(meta)] = ripple::strHex(txnPlusMeta.metadata);
|
obj = toJsonWithBinaryTx(txnPlusMeta, ctx.apiVersion);
|
||||||
obj[JS(tx_blob)] = ripple::strHex(txnPlusMeta.transaction);
|
|
||||||
obj[JS(ledger_index)] = txnPlusMeta.ledgerSequence;
|
obj[JS(ledger_index)] = txnPlusMeta.ledgerSequence;
|
||||||
// only clio has this field
|
|
||||||
obj[JS(date)] = txnPlusMeta.date;
|
obj[JS(date)] = txnPlusMeta.date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,10 @@ TransactionEntryHandler::process(TransactionEntryHandler::Input input, Context c
|
|||||||
if (auto status = std::get_if<Status>(&lgrInfoOrStatus))
|
if (auto status = std::get_if<Status>(&lgrInfoOrStatus))
|
||||||
return Error{*status};
|
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);
|
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
|
// Note: transaction_entry is meant to only search a specified ledger for
|
||||||
// the specified transaction. tx searches the entire range of history. For
|
// the specified transaction. tx searches the entire range of history. For
|
||||||
@@ -43,16 +46,13 @@ TransactionEntryHandler::process(TransactionEntryHandler::Input input, Context c
|
|||||||
// the API for transaction_entry says the method only searches the specified
|
// the API for transaction_entry says the method only searches the specified
|
||||||
// ledger; we simulate that here by returning not found if the transaction
|
// ledger; we simulate that here by returning not found if the transaction
|
||||||
// is in a different ledger than the one specified.
|
// 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."}};
|
return Error{Status{RippledError::rpcTXN_NOT_FOUND, "transactionNotFound", "Transaction not found."}};
|
||||||
|
|
||||||
auto output = TransactionEntryHandler::Output{};
|
|
||||||
auto [txn, meta] = toExpandedJson(*dbRet, ctx.apiVersion);
|
auto [txn, meta] = toExpandedJson(*dbRet, ctx.apiVersion);
|
||||||
|
|
||||||
output.tx = std::move(txn);
|
output.tx = std::move(txn);
|
||||||
output.metadata = std::move(meta);
|
output.metadata = std::move(meta);
|
||||||
output.ledgerIndex = lgrInfo.seq;
|
|
||||||
output.ledgerHash = ripple::strHex(lgrInfo.hash);
|
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@@ -60,13 +60,22 @@ TransactionEntryHandler::process(TransactionEntryHandler::Input input, Context c
|
|||||||
void
|
void
|
||||||
tag_invoke(boost::json::value_from_tag, boost::json::value& jv, TransactionEntryHandler::Output const& output)
|
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 = {
|
jv = {
|
||||||
{JS(validated), output.validated},
|
{JS(validated), output.validated},
|
||||||
{JS(metadata), output.metadata},
|
{metaKey, output.metadata},
|
||||||
{JS(tx_json), output.tx},
|
{JS(tx_json), output.tx},
|
||||||
{JS(ledger_index), output.ledgerIndex},
|
{JS(ledger_index), output.ledgerHeader->seq},
|
||||||
{JS(ledger_hash), output.ledgerHash},
|
{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
|
TransactionEntryHandler::Input
|
||||||
|
|||||||
@@ -37,13 +37,13 @@ class TransactionEntryHandler {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
struct Output {
|
struct Output {
|
||||||
uint32_t ledgerIndex;
|
std::optional<ripple::LedgerHeader> ledgerHeader;
|
||||||
std::string ledgerHash;
|
|
||||||
// TODO: use a better type for this
|
// TODO: use a better type for this
|
||||||
boost::json::object metadata;
|
boost::json::object metadata;
|
||||||
boost::json::object tx;
|
boost::json::object tx;
|
||||||
// validated should be sent via framework
|
// validated should be sent via framework
|
||||||
bool validated = true;
|
bool validated = true;
|
||||||
|
uint32_t apiVersion;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Input {
|
struct Input {
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ public:
|
|||||||
std::optional<boost::json::object> tx{};
|
std::optional<boost::json::object> tx{};
|
||||||
std::optional<std::string> metaStr{};
|
std::optional<std::string> metaStr{};
|
||||||
std::optional<std::string> txStr{};
|
std::optional<std::string> txStr{};
|
||||||
std::optional<std::string> ctid{}; // ctid when binary=true
|
std::optional<std::string> ctid{}; // ctid when binary=true
|
||||||
|
std::optional<ripple::LedgerHeader> ledgerHeader{}; // ledger hash when apiVersion >= 2
|
||||||
uint32_t apiVersion = 0u;
|
uint32_t apiVersion = 0u;
|
||||||
bool validated = true;
|
bool validated = true;
|
||||||
};
|
};
|
||||||
@@ -170,6 +171,10 @@ public:
|
|||||||
output.date = dbResponse->date;
|
output.date = dbResponse->date;
|
||||||
output.ledgerIndex = dbResponse->ledgerSequence;
|
output.ledgerIndex = dbResponse->ledgerSequence;
|
||||||
|
|
||||||
|
// fetch ledger hash
|
||||||
|
if (ctx.apiVersion > 1u)
|
||||||
|
output.ledgerHeader = sharedPtrBackend_->fetchLedgerBySequence(dbResponse->ledgerSequence, ctx.yield);
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,23 +197,60 @@ private:
|
|||||||
friend void
|
friend void
|
||||||
tag_invoke(boost::json::value_from_tag, boost::json::value& jv, Output const& output)
|
tag_invoke(boost::json::value_from_tag, boost::json::value& jv, Output const& output)
|
||||||
{
|
{
|
||||||
auto obj = boost::json::object{};
|
auto const getJsonV1 = [&]() {
|
||||||
|
auto obj = boost::json::object{};
|
||||||
|
|
||||||
if (output.tx) {
|
if (output.tx) {
|
||||||
obj = *output.tx;
|
obj = *output.tx;
|
||||||
obj[JS(meta)] = *output.meta;
|
obj[JS(meta)] = *output.meta;
|
||||||
} else {
|
} else {
|
||||||
obj[JS(meta)] = *output.metaStr;
|
obj[JS(meta)] = *output.metaStr;
|
||||||
obj[JS(tx)] = *output.txStr;
|
obj[JS(tx)] = *output.txStr;
|
||||||
obj[JS(hash)] = output.hash;
|
obj[JS(hash)] = output.hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
obj[JS(validated)] = output.validated;
|
obj[JS(validated)] = output.validated;
|
||||||
obj[JS(date)] = output.date;
|
obj[JS(date)] = output.date;
|
||||||
obj[JS(ledger_index)] = output.ledgerIndex;
|
obj[JS(ledger_index)] = output.ledgerIndex;
|
||||||
|
|
||||||
if (output.apiVersion < 2u)
|
|
||||||
obj[JS(inLedger)] = output.ledgerIndex;
|
obj[JS(inLedger)] = output.ledgerIndex;
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto const getJsonV2 = [&]() {
|
||||||
|
auto obj = boost::json::object{};
|
||||||
|
|
||||||
|
if (output.tx) {
|
||||||
|
obj[JS(tx_json)] = *output.tx;
|
||||||
|
obj[JS(tx_json)].as_object()[JS(date)] = output.date;
|
||||||
|
obj[JS(tx_json)].as_object()[JS(ledger_index)] = output.ledgerIndex;
|
||||||
|
// move ctid from tx_json to root
|
||||||
|
if (obj[JS(tx_json)].as_object().contains(JS(ctid))) {
|
||||||
|
obj[JS(ctid)] = obj[JS(tx_json)].as_object()[JS(ctid)];
|
||||||
|
obj[JS(tx_json)].as_object().erase(JS(ctid));
|
||||||
|
}
|
||||||
|
// move hash from tx_json to root
|
||||||
|
if (obj[JS(tx_json)].as_object().contains(JS(hash))) {
|
||||||
|
obj[JS(hash)] = obj[JS(tx_json)].as_object()[JS(hash)];
|
||||||
|
obj[JS(tx_json)].as_object().erase(JS(hash));
|
||||||
|
}
|
||||||
|
obj[JS(meta)] = *output.meta;
|
||||||
|
} else {
|
||||||
|
obj[JS(meta_blob)] = *output.metaStr;
|
||||||
|
obj[JS(tx_blob)] = *output.txStr;
|
||||||
|
obj[JS(hash)] = output.hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj[JS(validated)] = output.validated;
|
||||||
|
obj[JS(ledger_index)] = output.ledgerIndex;
|
||||||
|
|
||||||
|
if (output.ledgerHeader) {
|
||||||
|
obj[JS(ledger_hash)] = ripple::strHex(output.ledgerHeader->hash);
|
||||||
|
obj[JS(close_time_iso)] = ripple::to_string_iso(output.ledgerHeader->closeTime);
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto obj = output.apiVersion > 1u ? getJsonV2() : getJsonV1();
|
||||||
|
|
||||||
if (output.ctid)
|
if (output.ctid)
|
||||||
obj[JS(ctid)] = *output.ctid;
|
obj[JS(ctid)] = *output.ctid;
|
||||||
|
|||||||
@@ -418,3 +418,54 @@ TEST_F(RPCHelpersTest, DeliverMaxAliasV2)
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCHelpersTest, LedgerHeaderJson)
|
||||||
|
{
|
||||||
|
auto const ledgerHeader = CreateLedgerInfo(INDEX1, 30);
|
||||||
|
auto const binJson = toJson(ledgerHeader, true);
|
||||||
|
|
||||||
|
auto constexpr EXPECTBIN = R"({
|
||||||
|
"ledger_data": "0000001E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"closed": true
|
||||||
|
})";
|
||||||
|
EXPECT_EQ(binJson, boost::json::parse(EXPECTBIN));
|
||||||
|
|
||||||
|
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);
|
||||||
|
// remove platform-related close_time_human field
|
||||||
|
json.erase(JS(close_time_human));
|
||||||
|
EXPECT_EQ(json, boost::json::parse(EXPECTJSON));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCHelpersTest, TransactionAndMetadataBinaryJsonV1)
|
||||||
|
{
|
||||||
|
auto const txMeta = CreateAcceptNFTOfferTxWithMetadata(ACCOUNT, 30, 1, INDEX1);
|
||||||
|
auto const json = toJsonWithBinaryTx(txMeta, 1);
|
||||||
|
EXPECT_TRUE(json.contains(JS(tx_blob)));
|
||||||
|
EXPECT_TRUE(json.contains(JS(meta)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCHelpersTest, TransactionAndMetadataBinaryJsonV2)
|
||||||
|
{
|
||||||
|
auto const txMeta = CreateAcceptNFTOfferTxWithMetadata(ACCOUNT, 30, 1, INDEX1);
|
||||||
|
auto const json = toJsonWithBinaryTx(txMeta, 2);
|
||||||
|
EXPECT_TRUE(json.contains(JS(tx_blob)));
|
||||||
|
EXPECT_TRUE(json.contains(JS(meta_blob)));
|
||||||
|
}
|
||||||
|
|||||||
@@ -670,6 +670,64 @@ TEST_F(RPCAccountTxHandlerTest, BinaryTrue)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCAccountTxHandlerTest, BinaryTrueV2)
|
||||||
|
{
|
||||||
|
mockBackendPtr->updateRange(MINSEQ); // min
|
||||||
|
mockBackendPtr->updateRange(MAXSEQ); // max
|
||||||
|
MockBackend* rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
|
||||||
|
ASSERT_NE(rawBackendPtr, nullptr);
|
||||||
|
auto const transactions = genTransactions(MINSEQ + 1, MAXSEQ - 1);
|
||||||
|
auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}};
|
||||||
|
EXPECT_CALL(
|
||||||
|
*rawBackendPtr,
|
||||||
|
fetchAccountTransactions(
|
||||||
|
testing::_,
|
||||||
|
testing::_,
|
||||||
|
false,
|
||||||
|
testing::Optional(testing::Eq(TransactionsCursor{MAXSEQ, INT32_MAX})),
|
||||||
|
testing::_
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.WillOnce(Return(transCursor));
|
||||||
|
|
||||||
|
runSpawn([&, this](auto yield) {
|
||||||
|
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
|
||||||
|
auto const static input = json::parse(fmt::format(
|
||||||
|
R"({{
|
||||||
|
"account": "{}",
|
||||||
|
"ledger_index_min": {},
|
||||||
|
"ledger_index_max": {},
|
||||||
|
"binary": true
|
||||||
|
}})",
|
||||||
|
ACCOUNT,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
));
|
||||||
|
auto const output = handler.process(input, Context{.yield = yield, .apiVersion = 2u});
|
||||||
|
ASSERT_TRUE(output);
|
||||||
|
EXPECT_EQ(output->at("account").as_string(), ACCOUNT);
|
||||||
|
EXPECT_EQ(output->at("ledger_index_min").as_uint64(), MINSEQ);
|
||||||
|
EXPECT_EQ(output->at("ledger_index_max").as_uint64(), MAXSEQ);
|
||||||
|
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger": 12, "seq": 34})"));
|
||||||
|
EXPECT_EQ(output->at("transactions").as_array().size(), 2);
|
||||||
|
EXPECT_EQ(
|
||||||
|
output->at("transactions").as_array()[0].as_object().at("meta_blob").as_string(),
|
||||||
|
"201C00000000F8E5110061E762400000000000001681144B4E9C06F24296074F7B"
|
||||||
|
"C48F92A97916C6DC5EA9E1E1E5110061E76240000000000000178114D31252CF90"
|
||||||
|
"2EF8DD8451243869B38667CBD89DF3E1E1F1031000"
|
||||||
|
);
|
||||||
|
EXPECT_EQ(
|
||||||
|
output->at("transactions").as_array()[0].as_object().at("tx_blob").as_string(),
|
||||||
|
"120000240000002061400000000000000168400000000000000173047465737481"
|
||||||
|
"144B4E9C06F24296074F7BC48F92A97916C6DC5EA98314D31252CF902EF8DD8451"
|
||||||
|
"243869B38667CBD89DF3"
|
||||||
|
);
|
||||||
|
EXPECT_FALSE(output->at("transactions").as_array()[0].as_object().contains("date"));
|
||||||
|
EXPECT_FALSE(output->at("transactions").as_array()[0].as_object().contains("inLedger"));
|
||||||
|
EXPECT_FALSE(output->as_object().contains("limit"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(RPCAccountTxHandlerTest, LimitAndMarker)
|
TEST_F(RPCAccountTxHandlerTest, LimitAndMarker)
|
||||||
{
|
{
|
||||||
mockBackendPtr->updateRange(MINSEQ); // min
|
mockBackendPtr->updateRange(MINSEQ); // min
|
||||||
@@ -1287,7 +1345,11 @@ TEST_F(RPCAccountTxHandlerTest, NFTTxs_API_v2)
|
|||||||
"TransactionResult": "tesSUCCESS",
|
"TransactionResult": "tesSUCCESS",
|
||||||
"nftoken_id": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF"
|
"nftoken_id": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF"
|
||||||
},
|
},
|
||||||
"tx":
|
"hash": "C74463F49CFDCBEF3E9902672719918CDE5042DC7E7660BEBD1D1105C4B6DFF4",
|
||||||
|
"ledger_index": 11,
|
||||||
|
"ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
||||||
|
"close_time_iso": "2000-01-01T00:00:00Z",
|
||||||
|
"tx_json":
|
||||||
{
|
{
|
||||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
"Fee": "50",
|
"Fee": "50",
|
||||||
@@ -1295,7 +1357,6 @@ TEST_F(RPCAccountTxHandlerTest, NFTTxs_API_v2)
|
|||||||
"Sequence": 1,
|
"Sequence": 1,
|
||||||
"SigningPubKey": "74657374",
|
"SigningPubKey": "74657374",
|
||||||
"TransactionType": "NFTokenMint",
|
"TransactionType": "NFTokenMint",
|
||||||
"hash": "C74463F49CFDCBEF3E9902672719918CDE5042DC7E7660BEBD1D1105C4B6DFF4",
|
|
||||||
"ledger_index": 11,
|
"ledger_index": 11,
|
||||||
"date": 1
|
"date": 1
|
||||||
},
|
},
|
||||||
@@ -1321,7 +1382,11 @@ TEST_F(RPCAccountTxHandlerTest, NFTTxs_API_v2)
|
|||||||
"TransactionResult": "tesSUCCESS",
|
"TransactionResult": "tesSUCCESS",
|
||||||
"nftoken_id": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA"
|
"nftoken_id": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA"
|
||||||
},
|
},
|
||||||
"tx":
|
"hash": "7682BE6BCDE62F8142915DD852936623B68FC3839A8A424A6064B898702B0CDF",
|
||||||
|
"ledger_index": 11,
|
||||||
|
"ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
||||||
|
"close_time_iso": "2000-01-01T00:00:00Z",
|
||||||
|
"tx_json":
|
||||||
{
|
{
|
||||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
"Fee": "50",
|
"Fee": "50",
|
||||||
@@ -1329,7 +1394,6 @@ TEST_F(RPCAccountTxHandlerTest, NFTTxs_API_v2)
|
|||||||
"Sequence": 1,
|
"Sequence": 1,
|
||||||
"SigningPubKey": "74657374",
|
"SigningPubKey": "74657374",
|
||||||
"TransactionType": "NFTokenAcceptOffer",
|
"TransactionType": "NFTokenAcceptOffer",
|
||||||
"hash": "7682BE6BCDE62F8142915DD852936623B68FC3839A8A424A6064B898702B0CDF",
|
|
||||||
"ledger_index": 11,
|
"ledger_index": 11,
|
||||||
"date": 2
|
"date": 2
|
||||||
},
|
},
|
||||||
@@ -1368,7 +1432,11 @@ TEST_F(RPCAccountTxHandlerTest, NFTTxs_API_v2)
|
|||||||
"15FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF"
|
"15FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tx":
|
"hash": "9F82743EEB30065FB9CB92C61F0F064B5859C5A590FA811FAAAD9C988E5B47DB",
|
||||||
|
"ledger_index": 11,
|
||||||
|
"ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
||||||
|
"close_time_iso": "2000-01-01T00:00:00Z",
|
||||||
|
"tx_json":
|
||||||
{
|
{
|
||||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
"Fee": "50",
|
"Fee": "50",
|
||||||
@@ -1380,7 +1448,6 @@ TEST_F(RPCAccountTxHandlerTest, NFTTxs_API_v2)
|
|||||||
"Sequence": 1,
|
"Sequence": 1,
|
||||||
"SigningPubKey": "74657374",
|
"SigningPubKey": "74657374",
|
||||||
"TransactionType": "NFTokenCancelOffer",
|
"TransactionType": "NFTokenCancelOffer",
|
||||||
"hash": "9F82743EEB30065FB9CB92C61F0F064B5859C5A590FA811FAAAD9C988E5B47DB",
|
|
||||||
"ledger_index": 11,
|
"ledger_index": 11,
|
||||||
"date": 3
|
"date": 3
|
||||||
},
|
},
|
||||||
@@ -1403,7 +1470,11 @@ TEST_F(RPCAccountTxHandlerTest, NFTTxs_API_v2)
|
|||||||
"TransactionResult": "tesSUCCESS",
|
"TransactionResult": "tesSUCCESS",
|
||||||
"offer_id": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA"
|
"offer_id": "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA"
|
||||||
},
|
},
|
||||||
"tx":
|
"hash": "ECB1837EB7C7C0AC22ECDCCE59FDD4795C70E0B9D8F4E1C9A9408BB7EC75DA5C",
|
||||||
|
"ledger_index": 11,
|
||||||
|
"ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
||||||
|
"close_time_iso": "2000-01-01T00:00:00Z",
|
||||||
|
"tx_json":
|
||||||
{
|
{
|
||||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
"Amount": "123",
|
"Amount": "123",
|
||||||
@@ -1412,7 +1483,6 @@ TEST_F(RPCAccountTxHandlerTest, NFTTxs_API_v2)
|
|||||||
"Sequence": 1,
|
"Sequence": 1,
|
||||||
"SigningPubKey": "74657374",
|
"SigningPubKey": "74657374",
|
||||||
"TransactionType": "NFTokenCreateOffer",
|
"TransactionType": "NFTokenCreateOffer",
|
||||||
"hash": "ECB1837EB7C7C0AC22ECDCCE59FDD4795C70E0B9D8F4E1C9A9408BB7EC75DA5C",
|
|
||||||
"ledger_index": 11,
|
"ledger_index": 11,
|
||||||
"date": 4
|
"date": 4
|
||||||
},
|
},
|
||||||
@@ -1441,6 +1511,9 @@ TEST_F(RPCAccountTxHandlerTest, NFTTxs_API_v2)
|
|||||||
)
|
)
|
||||||
.Times(1);
|
.Times(1);
|
||||||
|
|
||||||
|
auto const ledgerInfo = CreateLedgerInfo(LEDGERHASH, 11);
|
||||||
|
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(transactions.size()).WillRepeatedly(Return(ledgerInfo));
|
||||||
|
|
||||||
runSpawn([&, this](auto yield) {
|
runSpawn([&, this](auto yield) {
|
||||||
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
|
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
|
||||||
auto const static input = json::parse(fmt::format(
|
auto const static input = json::parse(fmt::format(
|
||||||
@@ -1738,6 +1811,10 @@ generateTransactionTypeTestValues()
|
|||||||
})",
|
})",
|
||||||
R"([
|
R"([
|
||||||
{
|
{
|
||||||
|
"hash": "51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2",
|
||||||
|
"ledger_index": 30,
|
||||||
|
"ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
||||||
|
"close_time_iso": "2000-01-01T00:00:00Z",
|
||||||
"meta": {
|
"meta": {
|
||||||
"AffectedNodes": [
|
"AffectedNodes": [
|
||||||
{
|
{
|
||||||
@@ -1762,7 +1839,7 @@ generateTransactionTypeTestValues()
|
|||||||
"TransactionResult": "tesSUCCESS",
|
"TransactionResult": "tesSUCCESS",
|
||||||
"delivered_amount": "unavailable"
|
"delivered_amount": "unavailable"
|
||||||
},
|
},
|
||||||
"tx": {
|
"tx_json": {
|
||||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
"DeliverMax": "1",
|
"DeliverMax": "1",
|
||||||
"Destination": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
"Destination": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||||
@@ -1770,7 +1847,6 @@ generateTransactionTypeTestValues()
|
|||||||
"Sequence": 32,
|
"Sequence": 32,
|
||||||
"SigningPubKey": "74657374",
|
"SigningPubKey": "74657374",
|
||||||
"TransactionType": "Payment",
|
"TransactionType": "Payment",
|
||||||
"hash": "51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2",
|
|
||||||
"ledger_index": 30,
|
"ledger_index": 30,
|
||||||
"date": 1
|
"date": 1
|
||||||
},
|
},
|
||||||
@@ -1860,8 +1936,8 @@ TEST_P(AccountTxTransactionTypeTest, SpecificTransactionType)
|
|||||||
.Times(1);
|
.Times(1);
|
||||||
|
|
||||||
auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ);
|
auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ);
|
||||||
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1);
|
|
||||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _)).WillByDefault(Return(ledgerinfo));
|
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _)).WillByDefault(Return(ledgerinfo));
|
||||||
|
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _)).Times(Between(1, 2));
|
||||||
|
|
||||||
auto const testBundle = GetParam();
|
auto const testBundle = GetParam();
|
||||||
runSpawn([&, this](auto yield) {
|
runSpawn([&, this](auto yield) {
|
||||||
|
|||||||
@@ -229,6 +229,7 @@ TEST_F(RPCLedgerDataHandlerTest, NoMarker)
|
|||||||
"close_flags":0,
|
"close_flags":0,
|
||||||
"close_time":0,
|
"close_time":0,
|
||||||
"close_time_resolution":0,
|
"close_time_resolution":0,
|
||||||
|
"close_time_iso":"2000-01-01T00:00:00Z",
|
||||||
"ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
"ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
||||||
"ledger_index":"30",
|
"ledger_index":"30",
|
||||||
"parent_close_time":0,
|
"parent_close_time":0,
|
||||||
@@ -291,6 +292,7 @@ TEST_F(RPCLedgerDataHandlerTest, TypeFilter)
|
|||||||
"close_flags":0,
|
"close_flags":0,
|
||||||
"close_time":0,
|
"close_time":0,
|
||||||
"close_time_resolution":0,
|
"close_time_resolution":0,
|
||||||
|
"close_time_iso":"2000-01-01T00:00:00Z",
|
||||||
"ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
"ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
||||||
"ledger_index":"30",
|
"ledger_index":"30",
|
||||||
"parent_close_time":0,
|
"parent_close_time":0,
|
||||||
@@ -356,6 +358,7 @@ TEST_F(RPCLedgerDataHandlerTest, TypeFilterAMM)
|
|||||||
"close_flags":0,
|
"close_flags":0,
|
||||||
"close_time":0,
|
"close_time":0,
|
||||||
"close_time_resolution":0,
|
"close_time_resolution":0,
|
||||||
|
"close_time_iso":"2000-01-01T00:00:00Z",
|
||||||
"ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
"ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
||||||
"ledger_index":"30",
|
"ledger_index":"30",
|
||||||
"parent_close_time":0,
|
"parent_close_time":0,
|
||||||
@@ -418,6 +421,7 @@ TEST_F(RPCLedgerDataHandlerTest, OutOfOrder)
|
|||||||
"close_flags":0,
|
"close_flags":0,
|
||||||
"close_time":0,
|
"close_time":0,
|
||||||
"close_time_resolution":0,
|
"close_time_resolution":0,
|
||||||
|
"close_time_iso":"2000-01-01T00:00:00Z",
|
||||||
"ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
"ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
||||||
"ledger_index":"30",
|
"ledger_index":"30",
|
||||||
"parent_close_time":0,
|
"parent_close_time":0,
|
||||||
|
|||||||
@@ -263,6 +263,7 @@ TEST_F(RPCLedgerHandlerTest, Default)
|
|||||||
"close_time":0,
|
"close_time":0,
|
||||||
"close_time_resolution":0,
|
"close_time_resolution":0,
|
||||||
"closed":true,
|
"closed":true,
|
||||||
|
"close_time_iso":"2000-01-01T00:00:00Z",
|
||||||
"ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
"ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
||||||
"ledger_index":"30",
|
"ledger_index":"30",
|
||||||
"parent_close_time":0,
|
"parent_close_time":0,
|
||||||
@@ -445,6 +446,60 @@ TEST_F(RPCLedgerHandlerTest, TransactionsExpandBinary)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCLedgerHandlerTest, TransactionsExpandBinaryV2)
|
||||||
|
{
|
||||||
|
static auto constexpr expectedOut =
|
||||||
|
R"({
|
||||||
|
"ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
||||||
|
"ledger_index": 30,
|
||||||
|
"validated": true,
|
||||||
|
"ledger":{
|
||||||
|
"ledger_data": "0000001E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"closed": true,
|
||||||
|
"transactions": [
|
||||||
|
{
|
||||||
|
"hash": "70436A9332F7CD928FAEC1A41269A677739D8B11F108CE23AE23CBF0C9113F8C",
|
||||||
|
"tx_blob": "120000240000001E61400000000000006468400000000000000373047465737481144B4E9C06F24296074F7BC48F92A97916C6DC5EA98314D31252CF902EF8DD8451243869B38667CBD89DF3",
|
||||||
|
"meta_blob": "201C00000000F8E5110061E762400000000000006E81144B4E9C06F24296074F7BC48F92A97916C6DC5EA9E1E1E5110061E762400000000000001E8114D31252CF902EF8DD8451243869B38667CBD89DF3E1E1F1031000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "70436A9332F7CD928FAEC1A41269A677739D8B11F108CE23AE23CBF0C9113F8C",
|
||||||
|
"tx_blob": "120000240000001E61400000000000006468400000000000000373047465737481144B4E9C06F24296074F7BC48F92A97916C6DC5EA98314D31252CF902EF8DD8451243869B38667CBD89DF3",
|
||||||
|
"meta_blob": "201C00000000F8E5110061E762400000000000006E81144B4E9C06F24296074F7BC48F92A97916C6DC5EA9E1E1E5110061E762400000000000001E8114D31252CF902EF8DD8451243869B38667CBD89DF3E1E1F1031000"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})";
|
||||||
|
auto const rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
|
||||||
|
ASSERT_NE(rawBackendPtr, nullptr);
|
||||||
|
mockBackendPtr->updateRange(RANGEMIN);
|
||||||
|
mockBackendPtr->updateRange(RANGEMAX);
|
||||||
|
|
||||||
|
auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX);
|
||||||
|
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillOnce(Return(ledgerinfo));
|
||||||
|
|
||||||
|
TransactionAndMetadata t1;
|
||||||
|
t1.transaction = CreatePaymentTransactionObject(ACCOUNT, ACCOUNT2, 100, 3, RANGEMAX).getSerializer().peekData();
|
||||||
|
t1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30).getSerializer().peekData();
|
||||||
|
t1.ledgerSequence = RANGEMAX;
|
||||||
|
|
||||||
|
EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(RANGEMAX, _)).WillOnce(Return(std::vector{t1, t1}));
|
||||||
|
|
||||||
|
runSpawn([&, this](auto yield) {
|
||||||
|
auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}};
|
||||||
|
auto const req = json::parse(
|
||||||
|
R"({
|
||||||
|
"binary": true,
|
||||||
|
"expand": true,
|
||||||
|
"transactions": true
|
||||||
|
})"
|
||||||
|
);
|
||||||
|
auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 2u});
|
||||||
|
ASSERT_TRUE(output);
|
||||||
|
EXPECT_EQ(*output, json::parse(expectedOut));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(RPCLedgerHandlerTest, TransactionsExpandNotBinary)
|
TEST_F(RPCLedgerHandlerTest, TransactionsExpandNotBinary)
|
||||||
{
|
{
|
||||||
static auto constexpr expectedOut =
|
static auto constexpr expectedOut =
|
||||||
@@ -461,6 +516,7 @@ TEST_F(RPCLedgerHandlerTest, TransactionsExpandNotBinary)
|
|||||||
"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",
|
||||||
"parent_hash":"0000000000000000000000000000000000000000000000000000000000000000",
|
"parent_hash":"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"total_coins":"0",
|
"total_coins":"0",
|
||||||
"transaction_hash":"0000000000000000000000000000000000000000000000000000000000000000",
|
"transaction_hash":"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
@@ -538,6 +594,108 @@ TEST_F(RPCLedgerHandlerTest, TransactionsExpandNotBinary)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCLedgerHandlerTest, TransactionsExpandNotBinaryV2)
|
||||||
|
{
|
||||||
|
static auto constexpr expectedOut =
|
||||||
|
R"({
|
||||||
|
"ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
||||||
|
"ledger_index": 30,
|
||||||
|
"validated": true,
|
||||||
|
"ledger":{
|
||||||
|
"account_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"close_flags": 0,
|
||||||
|
"close_time": 0,
|
||||||
|
"close_time_resolution": 0,
|
||||||
|
"closed": true,
|
||||||
|
"ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
||||||
|
"ledger_index": "30",
|
||||||
|
"parent_close_time": 0,
|
||||||
|
"close_time_iso": "2000-01-01T00:00:00Z",
|
||||||
|
"parent_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"total_coins": "0",
|
||||||
|
"transaction_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"transactions":[
|
||||||
|
{
|
||||||
|
"validated": true,
|
||||||
|
"close_time_iso": "2000-01-01T00:00:00Z",
|
||||||
|
"hash": "70436A9332F7CD928FAEC1A41269A677739D8B11F108CE23AE23CBF0C9113F8C",
|
||||||
|
"ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
||||||
|
"ledger_index": "30",
|
||||||
|
"tx_json":
|
||||||
|
{
|
||||||
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
|
"DeliverMax": "100",
|
||||||
|
"Destination": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||||
|
"Fee": "3",
|
||||||
|
"Sequence": 30,
|
||||||
|
"SigningPubKey": "74657374",
|
||||||
|
"TransactionType": "Payment"
|
||||||
|
},
|
||||||
|
"meta":{
|
||||||
|
"AffectedNodes":[
|
||||||
|
{
|
||||||
|
"ModifiedNode":
|
||||||
|
{
|
||||||
|
"FinalFields":
|
||||||
|
{
|
||||||
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
|
"Balance": "110"
|
||||||
|
},
|
||||||
|
"LedgerEntryType": "AccountRoot"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ModifiedNode":
|
||||||
|
{
|
||||||
|
"FinalFields":
|
||||||
|
{
|
||||||
|
"Account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||||
|
"Balance": "30"
|
||||||
|
},
|
||||||
|
"LedgerEntryType": "AccountRoot"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"TransactionIndex": 0,
|
||||||
|
"TransactionResult": "tesSUCCESS",
|
||||||
|
"delivered_amount": "unavailable"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})";
|
||||||
|
auto const rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
|
||||||
|
ASSERT_NE(rawBackendPtr, nullptr);
|
||||||
|
mockBackendPtr->updateRange(RANGEMIN);
|
||||||
|
mockBackendPtr->updateRange(RANGEMAX);
|
||||||
|
|
||||||
|
auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX);
|
||||||
|
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillOnce(Return(ledgerinfo));
|
||||||
|
|
||||||
|
TransactionAndMetadata t1;
|
||||||
|
t1.transaction = CreatePaymentTransactionObject(ACCOUNT, ACCOUNT2, 100, 3, RANGEMAX).getSerializer().peekData();
|
||||||
|
t1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30).getSerializer().peekData();
|
||||||
|
t1.ledgerSequence = RANGEMAX;
|
||||||
|
|
||||||
|
EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(RANGEMAX, _)).WillOnce(Return(std::vector{t1}));
|
||||||
|
|
||||||
|
runSpawn([&, this](auto yield) {
|
||||||
|
auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}};
|
||||||
|
auto const req = json::parse(
|
||||||
|
R"({
|
||||||
|
"binary": false,
|
||||||
|
"expand": true,
|
||||||
|
"transactions": true
|
||||||
|
})"
|
||||||
|
);
|
||||||
|
auto output = handler.process(req, Context{.yield = yield, .apiVersion = 2u});
|
||||||
|
ASSERT_TRUE(output);
|
||||||
|
// remove human readable time, it is sightly different cross the platform
|
||||||
|
EXPECT_EQ(output->as_object().at("ledger").as_object().erase("close_time_human"), 1);
|
||||||
|
EXPECT_EQ(*output, json::parse(expectedOut));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(RPCLedgerHandlerTest, TransactionsNotExpand)
|
TEST_F(RPCLedgerHandlerTest, TransactionsNotExpand)
|
||||||
{
|
{
|
||||||
auto const rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
|
auto const rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
|
||||||
@@ -689,6 +847,7 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsEmtpy)
|
|||||||
"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",
|
||||||
"parent_hash":"0000000000000000000000000000000000000000000000000000000000000000",
|
"parent_hash":"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"total_coins":"0",
|
"total_coins":"0",
|
||||||
"transaction_hash":"0000000000000000000000000000000000000000000000000000000000000000",
|
"transaction_hash":"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
@@ -780,6 +939,7 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsTrueBinaryFalse)
|
|||||||
"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",
|
||||||
"parent_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
"parent_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"total_coins": "0",
|
"total_coins": "0",
|
||||||
"transaction_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
"transaction_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
|||||||
@@ -285,8 +285,110 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexSpecificForwardTrue)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RPCNFTHistoryHandlerTest, IndexSpecificForwardFalse)
|
TEST_F(RPCNFTHistoryHandlerTest, IndexSpecificForwardFalseV1)
|
||||||
{
|
{
|
||||||
|
auto constexpr OUTPUT = R"({
|
||||||
|
"nft_id": "00010000A7CAD27B688D14BA1A9FA5366554D6ADCF9CE0875B974D9F00000004",
|
||||||
|
"ledger_index_min": 11,
|
||||||
|
"ledger_index_max": 29,
|
||||||
|
"transactions":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"meta":
|
||||||
|
{
|
||||||
|
"AffectedNodes":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"ModifiedNode":{
|
||||||
|
"FinalFields":{
|
||||||
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
|
"Balance": "22"
|
||||||
|
},
|
||||||
|
"LedgerEntryType": "AccountRoot"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ModifiedNode":{
|
||||||
|
"FinalFields":{
|
||||||
|
"Account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||||
|
"Balance": "23"
|
||||||
|
},
|
||||||
|
"LedgerEntryType": "AccountRoot"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"TransactionIndex": 0,
|
||||||
|
"TransactionResult": "tesSUCCESS",
|
||||||
|
"delivered_amount": "unavailable"
|
||||||
|
},
|
||||||
|
"tx":
|
||||||
|
{
|
||||||
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
|
"Amount": "1",
|
||||||
|
"Destination": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||||
|
"Fee": "1",
|
||||||
|
"Sequence": 32,
|
||||||
|
"SigningPubKey": "74657374",
|
||||||
|
"TransactionType": "Payment",
|
||||||
|
"hash": "51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2",
|
||||||
|
"DeliverMax": "1",
|
||||||
|
"ledger_index": 11,
|
||||||
|
"date": 1
|
||||||
|
},
|
||||||
|
"validated": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"meta":
|
||||||
|
{
|
||||||
|
"AffectedNodes":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"ModifiedNode":{
|
||||||
|
"FinalFields":{
|
||||||
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
|
"Balance": "22"
|
||||||
|
},
|
||||||
|
"LedgerEntryType": "AccountRoot"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ModifiedNode":{
|
||||||
|
"FinalFields":{
|
||||||
|
"Account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||||
|
"Balance": "23"
|
||||||
|
},
|
||||||
|
"LedgerEntryType": "AccountRoot"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"TransactionIndex": 0,
|
||||||
|
"TransactionResult": "tesSUCCESS",
|
||||||
|
"delivered_amount": "unavailable"
|
||||||
|
},
|
||||||
|
"tx":
|
||||||
|
{
|
||||||
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
|
"Amount": "1",
|
||||||
|
"Destination": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||||
|
"Fee": "1",
|
||||||
|
"Sequence": 32,
|
||||||
|
"SigningPubKey": "74657374",
|
||||||
|
"TransactionType": "Payment",
|
||||||
|
"hash": "51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2",
|
||||||
|
"DeliverMax": "1",
|
||||||
|
"ledger_index": 29,
|
||||||
|
"date": 2
|
||||||
|
},
|
||||||
|
"validated": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validated": true,
|
||||||
|
"marker":
|
||||||
|
{
|
||||||
|
"ledger": 12,
|
||||||
|
"seq": 34
|
||||||
|
}
|
||||||
|
})";
|
||||||
mockBackendPtr->updateRange(MINSEQ); // min
|
mockBackendPtr->updateRange(MINSEQ); // min
|
||||||
mockBackendPtr->updateRange(MAXSEQ); // max
|
mockBackendPtr->updateRange(MAXSEQ); // max
|
||||||
MockBackend* rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
|
MockBackend* rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
|
||||||
@@ -321,12 +423,164 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexSpecificForwardFalse)
|
|||||||
));
|
));
|
||||||
auto const output = handler.process(input, Context{yield});
|
auto const output = handler.process(input, Context{yield});
|
||||||
ASSERT_TRUE(output);
|
ASSERT_TRUE(output);
|
||||||
EXPECT_EQ(output->at("nft_id").as_string(), NFTID);
|
EXPECT_EQ(output.value(), boost::json::parse(OUTPUT));
|
||||||
EXPECT_EQ(output->at("ledger_index_min").as_uint64(), MINSEQ + 1);
|
});
|
||||||
EXPECT_EQ(output->at("ledger_index_max").as_uint64(), MAXSEQ - 1);
|
}
|
||||||
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger":12,"seq":34})"));
|
|
||||||
EXPECT_EQ(output->at("transactions").as_array().size(), 2);
|
TEST_F(RPCNFTHistoryHandlerTest, IndexSpecificForwardFalseV2)
|
||||||
EXPECT_FALSE(output->as_object().contains("limit"));
|
{
|
||||||
|
auto constexpr OUTPUT = R"({
|
||||||
|
"nft_id": "00010000A7CAD27B688D14BA1A9FA5366554D6ADCF9CE0875B974D9F00000004",
|
||||||
|
"ledger_index_min": 11,
|
||||||
|
"ledger_index_max": 29,
|
||||||
|
"transactions":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"meta":
|
||||||
|
{
|
||||||
|
"AffectedNodes":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"ModifiedNode":
|
||||||
|
{
|
||||||
|
"FinalFields":
|
||||||
|
{
|
||||||
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
|
"Balance": "22"
|
||||||
|
},
|
||||||
|
"LedgerEntryType": "AccountRoot"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ModifiedNode":
|
||||||
|
{
|
||||||
|
"FinalFields":
|
||||||
|
{
|
||||||
|
"Account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||||
|
"Balance": "23"
|
||||||
|
},
|
||||||
|
"LedgerEntryType": "AccountRoot"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"TransactionIndex": 0,
|
||||||
|
"TransactionResult": "tesSUCCESS",
|
||||||
|
"delivered_amount": "unavailable"
|
||||||
|
},
|
||||||
|
"tx_json":
|
||||||
|
{
|
||||||
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
|
"Destination": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||||
|
"Fee": "1",
|
||||||
|
"Sequence": 32,
|
||||||
|
"SigningPubKey": "74657374",
|
||||||
|
"TransactionType": "Payment",
|
||||||
|
"DeliverMax": "1",
|
||||||
|
"ledger_index": 11,
|
||||||
|
"date": 1
|
||||||
|
},
|
||||||
|
"hash": "51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2",
|
||||||
|
"ledger_index": 11,
|
||||||
|
"close_time_iso": "2000-01-01T00:00:00Z",
|
||||||
|
"ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
||||||
|
"validated": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"meta":
|
||||||
|
{
|
||||||
|
"AffectedNodes":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"ModifiedNode":
|
||||||
|
{
|
||||||
|
"FinalFields":
|
||||||
|
{
|
||||||
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
|
"Balance": "22"
|
||||||
|
},
|
||||||
|
"LedgerEntryType": "AccountRoot"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ModifiedNode":
|
||||||
|
{
|
||||||
|
"FinalFields":
|
||||||
|
{
|
||||||
|
"Account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||||
|
"Balance": "23"
|
||||||
|
},
|
||||||
|
"LedgerEntryType": "AccountRoot"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"TransactionIndex": 0,
|
||||||
|
"TransactionResult": "tesSUCCESS",
|
||||||
|
"delivered_amount": "unavailable"
|
||||||
|
},
|
||||||
|
"tx_json":
|
||||||
|
{
|
||||||
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
|
"Destination": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||||
|
"Fee": "1",
|
||||||
|
"Sequence": 32,
|
||||||
|
"SigningPubKey": "74657374",
|
||||||
|
"TransactionType": "Payment",
|
||||||
|
"DeliverMax": "1",
|
||||||
|
"ledger_index": 29,
|
||||||
|
"date": 2
|
||||||
|
},
|
||||||
|
"hash": "51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2",
|
||||||
|
"ledger_index": 29,
|
||||||
|
"close_time_iso": "2000-01-01T00:00:00Z",
|
||||||
|
"ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
||||||
|
"validated": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validated": true,
|
||||||
|
"marker":
|
||||||
|
{
|
||||||
|
"ledger": 12,
|
||||||
|
"seq": 34
|
||||||
|
}
|
||||||
|
})";
|
||||||
|
mockBackendPtr->updateRange(MINSEQ); // min
|
||||||
|
mockBackendPtr->updateRange(MAXSEQ); // max
|
||||||
|
MockBackend* rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
|
||||||
|
ASSERT_NE(rawBackendPtr, nullptr);
|
||||||
|
auto const transactions = genTransactions(MINSEQ + 1, MAXSEQ - 1);
|
||||||
|
auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}};
|
||||||
|
EXPECT_CALL(
|
||||||
|
*rawBackendPtr,
|
||||||
|
fetchNFTTransactions(
|
||||||
|
testing::_,
|
||||||
|
testing::_,
|
||||||
|
false,
|
||||||
|
testing::Optional(testing::Eq(TransactionsCursor{MAXSEQ - 1, INT32_MAX})),
|
||||||
|
testing::_
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.WillOnce(Return(transCursor));
|
||||||
|
|
||||||
|
auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ);
|
||||||
|
ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo));
|
||||||
|
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(2);
|
||||||
|
|
||||||
|
runSpawn([&, this](auto yield) {
|
||||||
|
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
|
||||||
|
auto const static input = json::parse(fmt::format(
|
||||||
|
R"({{
|
||||||
|
"nft_id":"{}",
|
||||||
|
"ledger_index_min": {},
|
||||||
|
"ledger_index_max": {},
|
||||||
|
"forward": false
|
||||||
|
}})",
|
||||||
|
NFTID,
|
||||||
|
MINSEQ + 1,
|
||||||
|
MAXSEQ - 1
|
||||||
|
));
|
||||||
|
auto const output = handler.process(input, Context{.yield = yield, .apiVersion = 2u});
|
||||||
|
ASSERT_TRUE(output);
|
||||||
|
EXPECT_EQ(output.value(), boost::json::parse(OUTPUT));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,7 +670,7 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexNotSpecificForwardFalse)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(RPCNFTHistoryHandlerTest, BinaryTrue)
|
TEST_F(RPCNFTHistoryHandlerTest, BinaryTrueV1)
|
||||||
{
|
{
|
||||||
mockBackendPtr->updateRange(MINSEQ); // min
|
mockBackendPtr->updateRange(MINSEQ); // min
|
||||||
mockBackendPtr->updateRange(MAXSEQ); // max
|
mockBackendPtr->updateRange(MAXSEQ); // max
|
||||||
@@ -475,6 +729,64 @@ TEST_F(RPCNFTHistoryHandlerTest, BinaryTrue)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCNFTHistoryHandlerTest, BinaryTrueV2)
|
||||||
|
{
|
||||||
|
mockBackendPtr->updateRange(MINSEQ); // min
|
||||||
|
mockBackendPtr->updateRange(MAXSEQ); // max
|
||||||
|
MockBackend* rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
|
||||||
|
ASSERT_NE(rawBackendPtr, nullptr);
|
||||||
|
auto const transactions = genTransactions(MINSEQ + 1, MAXSEQ - 1);
|
||||||
|
auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}};
|
||||||
|
EXPECT_CALL(
|
||||||
|
*rawBackendPtr,
|
||||||
|
fetchNFTTransactions(
|
||||||
|
testing::_,
|
||||||
|
testing::_,
|
||||||
|
false,
|
||||||
|
testing::Optional(testing::Eq(TransactionsCursor{MAXSEQ, INT32_MAX})),
|
||||||
|
testing::_
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.WillOnce(Return(transCursor));
|
||||||
|
|
||||||
|
runSpawn([&, this](auto yield) {
|
||||||
|
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
|
||||||
|
auto const static input = json::parse(fmt::format(
|
||||||
|
R"({{
|
||||||
|
"nft_id":"{}",
|
||||||
|
"ledger_index_min": {},
|
||||||
|
"ledger_index_max": {},
|
||||||
|
"binary": true
|
||||||
|
}})",
|
||||||
|
NFTID,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
));
|
||||||
|
auto const output = handler.process(input, Context{.yield = yield, .apiVersion = 2u});
|
||||||
|
ASSERT_TRUE(output);
|
||||||
|
EXPECT_EQ(output->at("nft_id").as_string(), NFTID);
|
||||||
|
EXPECT_EQ(output->at("ledger_index_min").as_uint64(), MINSEQ);
|
||||||
|
EXPECT_EQ(output->at("ledger_index_max").as_uint64(), MAXSEQ);
|
||||||
|
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger":12,"seq":34})"));
|
||||||
|
EXPECT_EQ(output->at("transactions").as_array().size(), 2);
|
||||||
|
EXPECT_EQ(
|
||||||
|
output->at("transactions").as_array()[0].as_object().at("meta_blob").as_string(),
|
||||||
|
"201C00000000F8E5110061E762400000000000001681144B4E9C06F24296074F7B"
|
||||||
|
"C48F92A97916C6DC5EA9E1E1E5110061E76240000000000000178114D31252CF90"
|
||||||
|
"2EF8DD8451243869B38667CBD89DF3E1E1F1031000"
|
||||||
|
);
|
||||||
|
EXPECT_EQ(
|
||||||
|
output->at("transactions").as_array()[0].as_object().at("tx_blob").as_string(),
|
||||||
|
"120000240000002061400000000000000168400000000000000173047465737481"
|
||||||
|
"144B4E9C06F24296074F7BC48F92A97916C6DC5EA98314D31252CF902EF8DD8451"
|
||||||
|
"243869B38667CBD89DF3"
|
||||||
|
);
|
||||||
|
EXPECT_EQ(output->at("transactions").as_array()[0].as_object().at("date").as_uint64(), 1);
|
||||||
|
|
||||||
|
EXPECT_FALSE(output->as_object().contains("limit"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(RPCNFTHistoryHandlerTest, LimitAndMarker)
|
TEST_F(RPCNFTHistoryHandlerTest, LimitAndMarker)
|
||||||
{
|
{
|
||||||
mockBackendPtr->updateRange(MINSEQ); // min
|
mockBackendPtr->updateRange(MINSEQ); // min
|
||||||
|
|||||||
@@ -179,48 +179,49 @@ TEST_F(RPCTransactionEntryHandlerTest, LedgerSeqNotMatch)
|
|||||||
TEST_F(RPCTransactionEntryHandlerTest, NormalPath)
|
TEST_F(RPCTransactionEntryHandlerTest, NormalPath)
|
||||||
{
|
{
|
||||||
static auto constexpr OUTPUT = R"({
|
static auto constexpr OUTPUT = R"({
|
||||||
"metadata":{
|
"metadata":
|
||||||
|
{
|
||||||
"AffectedNodes":
|
"AffectedNodes":
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"CreatedNode":
|
"CreatedNode":
|
||||||
{
|
{
|
||||||
"LedgerEntryType":"Offer",
|
"LedgerEntryType": "Offer",
|
||||||
"NewFields":
|
"NewFields":
|
||||||
{
|
{
|
||||||
"TakerGets":"200",
|
"TakerGets": "200",
|
||||||
"TakerPays":
|
"TakerPays":
|
||||||
{
|
{
|
||||||
"currency":"0158415500000000C1F76FF6ECB0BAC600000000",
|
"currency": "0158415500000000C1F76FF6ECB0BAC600000000",
|
||||||
"issuer":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
"issuer": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
"value":"300"
|
"value": "300"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"TransactionIndex":100,
|
"TransactionIndex": 100,
|
||||||
"TransactionResult":"tesSUCCESS"
|
"TransactionResult": "tesSUCCESS"
|
||||||
},
|
},
|
||||||
"tx_json":
|
"tx_json":
|
||||||
{
|
{
|
||||||
"Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
"Fee":"2",
|
"Fee": "2",
|
||||||
"Sequence":100,
|
"Sequence": 100,
|
||||||
"SigningPubKey":"74657374",
|
"SigningPubKey": "74657374",
|
||||||
"TakerGets":
|
"TakerGets":
|
||||||
{
|
{
|
||||||
"currency":"0158415500000000C1F76FF6ECB0BAC600000000",
|
"currency": "0158415500000000C1F76FF6ECB0BAC600000000",
|
||||||
"issuer":"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
"issuer": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||||
"value":"200"
|
"value": "200"
|
||||||
},
|
},
|
||||||
"TakerPays":"300",
|
"TakerPays": "300",
|
||||||
"TransactionType":"OfferCreate",
|
"TransactionType": "OfferCreate",
|
||||||
"hash":"2E2FBAAFF767227FE4381C4BE9855986A6B9F96C62F6E443731AB36F7BBB8A08"
|
"hash": "2E2FBAAFF767227FE4381C4BE9855986A6B9F96C62F6E443731AB36F7BBB8A08"
|
||||||
},
|
},
|
||||||
"ledger_index":30,
|
"ledger_index": 30,
|
||||||
"ledger_hash":"E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC322",
|
"ledger_hash": "E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC322",
|
||||||
"validated":true
|
"validated": true
|
||||||
})";
|
})";
|
||||||
auto const rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
|
auto const rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
|
||||||
ASSERT_NE(rawBackendPtr, nullptr);
|
ASSERT_NE(rawBackendPtr, nullptr);
|
||||||
@@ -253,3 +254,81 @@ TEST_F(RPCTransactionEntryHandlerTest, NormalPath)
|
|||||||
EXPECT_EQ(json::parse(OUTPUT), *output);
|
EXPECT_EQ(json::parse(OUTPUT), *output);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(RPCTransactionEntryHandlerTest, NormalPathV2)
|
||||||
|
{
|
||||||
|
static auto constexpr OUTPUT = R"({
|
||||||
|
"meta":
|
||||||
|
{
|
||||||
|
"AffectedNodes":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"CreatedNode":
|
||||||
|
{
|
||||||
|
"LedgerEntryType": "Offer",
|
||||||
|
"NewFields":
|
||||||
|
{
|
||||||
|
"TakerGets": "200",
|
||||||
|
"TakerPays":
|
||||||
|
{
|
||||||
|
"currency": "0158415500000000C1F76FF6ECB0BAC600000000",
|
||||||
|
"issuer": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
|
"value": "300"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"TransactionIndex": 100,
|
||||||
|
"TransactionResult": "tesSUCCESS"
|
||||||
|
},
|
||||||
|
"tx_json":
|
||||||
|
{
|
||||||
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
|
"Fee": "2",
|
||||||
|
"Sequence": 100,
|
||||||
|
"SigningPubKey": "74657374",
|
||||||
|
"TakerGets":
|
||||||
|
{
|
||||||
|
"currency": "0158415500000000C1F76FF6ECB0BAC600000000",
|
||||||
|
"issuer": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||||
|
"value": "200"
|
||||||
|
},
|
||||||
|
"TakerPays": "300",
|
||||||
|
"TransactionType": "OfferCreate"
|
||||||
|
},
|
||||||
|
"ledger_index": 30,
|
||||||
|
"ledger_hash": "E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC322",
|
||||||
|
"close_time_iso": "2000-01-01T00:00:00Z",
|
||||||
|
"hash": "2E2FBAAFF767227FE4381C4BE9855986A6B9F96C62F6E443731AB36F7BBB8A08",
|
||||||
|
"validated": true
|
||||||
|
})";
|
||||||
|
auto const rawBackendPtr = dynamic_cast<MockBackend*>(mockBackendPtr.get());
|
||||||
|
ASSERT_NE(rawBackendPtr, nullptr);
|
||||||
|
TransactionAndMetadata tx;
|
||||||
|
tx.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT, 100, 200, 300).getSerializer().peekData();
|
||||||
|
tx.transaction =
|
||||||
|
CreateCreateOfferTransactionObject(ACCOUNT, 2, 100, CURRENCY, ACCOUNT2, 200, 300).getSerializer().peekData();
|
||||||
|
tx.date = 123456;
|
||||||
|
tx.ledgerSequence = 30;
|
||||||
|
EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx));
|
||||||
|
|
||||||
|
mockBackendPtr->updateRange(10); // min
|
||||||
|
mockBackendPtr->updateRange(tx.ledgerSequence); // max
|
||||||
|
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(CreateLedgerInfo(INDEX, tx.ledgerSequence)));
|
||||||
|
|
||||||
|
runSpawn([&, this](auto yield) {
|
||||||
|
auto const handler = AnyHandler{TransactionEntryHandler{mockBackendPtr}};
|
||||||
|
auto const req = json::parse(fmt::format(
|
||||||
|
R"({{
|
||||||
|
"tx_hash": "{}",
|
||||||
|
"ledger_index": {}
|
||||||
|
}})",
|
||||||
|
TXNID,
|
||||||
|
tx.ledgerSequence
|
||||||
|
));
|
||||||
|
auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 2});
|
||||||
|
ASSERT_TRUE(output);
|
||||||
|
EXPECT_EQ(json::parse(OUTPUT), *output);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,12 +33,13 @@ using TestTxHandler = BaseTxHandler<MockETLService>;
|
|||||||
auto constexpr static TXNID = "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DD";
|
auto constexpr static TXNID = "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DD";
|
||||||
auto constexpr static NFTID = "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF";
|
auto constexpr static NFTID = "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DF";
|
||||||
auto constexpr static NFTID2 = "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA";
|
auto constexpr static NFTID2 = "05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DA";
|
||||||
|
constexpr static auto LEDGERHASH = "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652";
|
||||||
auto constexpr static ACCOUNT = "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn";
|
auto constexpr static ACCOUNT = "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn";
|
||||||
auto constexpr static ACCOUNT2 = "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun";
|
auto constexpr static ACCOUNT2 = "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun";
|
||||||
auto constexpr static CURRENCY = "0158415500000000C1F76FF6ECB0BAC600000000";
|
auto constexpr static CURRENCY = "0158415500000000C1F76FF6ECB0BAC600000000";
|
||||||
constexpr static auto CTID = "C002807000010002"; // seq 163952 txindex 1 netid 2
|
constexpr static auto CTID = "C002807000010002"; // seq 163952 txindex 1 netid 2
|
||||||
constexpr static auto SEQ_FROM_CTID = 163952;
|
constexpr static auto SEQ_FROM_CTID = 163952;
|
||||||
auto constexpr static DEFAULT_OUT = R"({
|
auto constexpr static DEFAULT_OUT_1 = R"({
|
||||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
"Fee": "2",
|
"Fee": "2",
|
||||||
"Sequence": 100,
|
"Sequence": 100,
|
||||||
@@ -72,6 +73,49 @@ auto constexpr static DEFAULT_OUT = R"({
|
|||||||
},
|
},
|
||||||
"date": 123456,
|
"date": 123456,
|
||||||
"ledger_index": 100,
|
"ledger_index": 100,
|
||||||
|
"inLedger": 100,
|
||||||
|
"validated": true
|
||||||
|
})";
|
||||||
|
|
||||||
|
auto constexpr static DEFAULT_OUT_2 = R"({
|
||||||
|
"hash": "2E2FBAAFF767227FE4381C4BE9855986A6B9F96C62F6E443731AB36F7BBB8A08",
|
||||||
|
"ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652",
|
||||||
|
"ledger_index": 100,
|
||||||
|
"meta": {
|
||||||
|
"AffectedNodes": [
|
||||||
|
{
|
||||||
|
"CreatedNode": {
|
||||||
|
"LedgerEntryType": "Offer",
|
||||||
|
"NewFields": {
|
||||||
|
"TakerGets": "200",
|
||||||
|
"TakerPays": {
|
||||||
|
"currency": "0158415500000000C1F76FF6ECB0BAC600000000",
|
||||||
|
"issuer": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
|
"value": "300"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"TransactionIndex": 100,
|
||||||
|
"TransactionResult": "tesSUCCESS"
|
||||||
|
},
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||||
|
"date": 123456,
|
||||||
|
"Fee": "2",
|
||||||
|
"ledger_index": 100,
|
||||||
|
"Sequence": 100,
|
||||||
|
"SigningPubKey": "74657374",
|
||||||
|
"TakerGets": {
|
||||||
|
"currency": "0158415500000000C1F76FF6ECB0BAC600000000",
|
||||||
|
"issuer": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||||
|
"value": "200"
|
||||||
|
},
|
||||||
|
"TakerPays": "300",
|
||||||
|
"TransactionType": "OfferCreate"
|
||||||
|
},
|
||||||
|
"close_time_iso": "2000-01-01T00:00:00Z",
|
||||||
"validated": true
|
"validated": true
|
||||||
})";
|
})";
|
||||||
|
|
||||||
@@ -282,9 +326,7 @@ TEST_F(RPCTxTest, DefaultParameter_API_v1)
|
|||||||
auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 1u});
|
auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 1u});
|
||||||
ASSERT_TRUE(output);
|
ASSERT_TRUE(output);
|
||||||
|
|
||||||
auto v1Output = json::parse(DEFAULT_OUT);
|
EXPECT_EQ(*output, json::parse(DEFAULT_OUT_1));
|
||||||
v1Output.as_object()[JS(inLedger)] = v1Output.as_object()[JS(ledger_index)];
|
|
||||||
EXPECT_EQ(*output, v1Output);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,6 +375,7 @@ TEST_F(RPCTxTest, PaymentTx_API_v2)
|
|||||||
tx.ledgerSequence = 100;
|
tx.ledgerSequence = 100;
|
||||||
|
|
||||||
EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx));
|
EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx));
|
||||||
|
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence(tx.ledgerSequence, _)).WillOnce(Return(std::nullopt));
|
||||||
|
|
||||||
auto const rawETLPtr = dynamic_cast<MockETLService*>(mockETLServicePtr.get());
|
auto const rawETLPtr = dynamic_cast<MockETLService*>(mockETLServicePtr.get());
|
||||||
ASSERT_NE(rawETLPtr, nullptr);
|
ASSERT_NE(rawETLPtr, nullptr);
|
||||||
@@ -349,8 +392,9 @@ TEST_F(RPCTxTest, PaymentTx_API_v2)
|
|||||||
));
|
));
|
||||||
auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 2u});
|
auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 2u});
|
||||||
ASSERT_TRUE(output);
|
ASSERT_TRUE(output);
|
||||||
EXPECT_TRUE(output->as_object().contains("DeliverMax"));
|
EXPECT_TRUE(output->as_object().contains("tx_json"));
|
||||||
EXPECT_FALSE(output->as_object().contains("Amount"));
|
EXPECT_TRUE(output->as_object().at("tx_json").as_object().contains("DeliverMax"));
|
||||||
|
EXPECT_FALSE(output->as_object().at("tx_json").as_object().contains("Amount"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,6 +411,8 @@ TEST_F(RPCTxTest, DefaultParameter_API_v2)
|
|||||||
tx.ledgerSequence = 100;
|
tx.ledgerSequence = 100;
|
||||||
|
|
||||||
EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx));
|
EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx));
|
||||||
|
auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, tx.ledgerSequence);
|
||||||
|
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence(tx.ledgerSequence, _)).WillOnce(Return(ledgerinfo));
|
||||||
|
|
||||||
auto const rawETLPtr = dynamic_cast<MockETLService*>(mockETLServicePtr.get());
|
auto const rawETLPtr = dynamic_cast<MockETLService*>(mockETLServicePtr.get());
|
||||||
ASSERT_NE(rawETLPtr, nullptr);
|
ASSERT_NE(rawETLPtr, nullptr);
|
||||||
@@ -383,7 +429,7 @@ TEST_F(RPCTxTest, DefaultParameter_API_v2)
|
|||||||
));
|
));
|
||||||
auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 2u});
|
auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 2u});
|
||||||
ASSERT_TRUE(output);
|
ASSERT_TRUE(output);
|
||||||
EXPECT_EQ(*output, json::parse(DEFAULT_OUT));
|
EXPECT_EQ(*output, json::parse(DEFAULT_OUT_2));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user