delivered amount

This commit is contained in:
CJ Cobb
2021-07-22 20:30:44 +00:00
parent 41bd820a2a
commit 97f6081390
6 changed files with 160 additions and 80 deletions

View File

@@ -7,7 +7,6 @@ template <class T, class F>
void
processAsyncWriteResponse(T& requestParams, CassFuture* fut, F func)
{
BOOST_LOG_TRIVIAL(debug) << __func__ << " Processing async write response";
CassandraBackend const& backend = *requestParams.backend;
auto rc = cass_future_error_code(fut);
if (rc != CASS_OK)

View File

@@ -1,6 +1,56 @@
#include <backend/BackendInterface.h>
#include <handlers/RPCHelpers.h>
#include <handlers/Status.h>
#include <backend/BackendInterface.h>
std::optional<ripple::STAmount>
getDeliveredAmount(
std::shared_ptr<ripple::STTx const> const& txn,
std::shared_ptr<ripple::STObject const> const& meta,
uint32_t ledgerSequence)
{
if (meta->isFieldPresent(ripple::sfDeliveredAmount))
return meta->getFieldAmount(ripple::sfDeliveredAmount);
if (txn->isFieldPresent(ripple::sfAmount))
{
using namespace std::chrono_literals;
// Ledger 4594095 is the first ledger in which the DeliveredAmount field
// was present when a partial payment was made and its absence indicates
// that the amount delivered is listed in the Amount field.
//
// If the ledger closed long after the DeliveredAmount code was deployed
// then its absence indicates that the amount delivered is listed in the
// Amount field. DeliveredAmount went live January 24, 2014.
// 446000000 is in Feb 2014, well after DeliveredAmount went live
if (ledgerSequence >= 4594095)
{
return txn->getFieldAmount(ripple::sfAmount);
}
}
return {};
}
bool
canHaveDeliveredAmount(
std::shared_ptr<ripple::STTx const> const& txn,
std::shared_ptr<ripple::STObject const> const& meta)
{
ripple::TxType const tt{txn->getTxnType()};
if (tt != ripple::ttPAYMENT && tt != ripple::ttCHECK_CASH &&
tt != ripple::ttACCOUNT_DELETE)
return false;
/*
if (tt == ttCHECK_CASH && !getFix1623Enabled())
return false;
*/
if (ripple::TER::fromInt(meta->getFieldU8(ripple::sfTransactionResult)) !=
ripple::tesSUCCESS)
return false;
return true;
}
std::optional<ripple::AccountID>
accountFromStringStrict(std::string const& account)
@@ -76,6 +126,23 @@ toJson(ripple::STBase const& obj)
return value.as_object();
}
std::pair<boost::json::object, boost::json::object>
toExpandedJson(Backend::TransactionAndMetadata const& blobs)
{
auto [txn, meta] = deserializeTxPlusMeta(blobs);
auto txnJson = toJson(*txn);
auto metaJson = toJson(*meta);
if (canHaveDeliveredAmount(txn, meta))
{
if (auto amt = getDeliveredAmount(txn, meta, blobs.ledgerSequence))
metaJson["delivered_amount"] =
toBoostJson(amt->getJson(ripple::JsonOptions::include_date));
else
metaJson["delivered_amount"] = "unavailable";
}
return {txnJson, metaJson};
}
boost::json::object
toJson(ripple::TxMeta const& meta)
{
@@ -88,8 +155,7 @@ toJson(ripple::TxMeta const& meta)
boost::json::value
toBoostJson(Json::Value const& value)
{
boost::json::value boostValue =
boost::json::parse(value.toStyledString());
boost::json::value boostValue = boost::json::parse(value.toStyledString());
return boostValue;
}
@@ -138,14 +204,15 @@ ledgerInfoFromRequest(RPC::Context const& ctx)
if (!hashValue.is_null())
{
if (!hashValue.is_string())
return RPC::Status{RPC::Error::rpcINVALID_PARAMS, "ledgerHashNotString"};
return RPC::Status{
RPC::Error::rpcINVALID_PARAMS, "ledgerHashNotString"};
ripple::uint256 ledgerHash;
if (!ledgerHash.parseHex(hashValue.as_string().c_str()))
return RPC::Status{RPC::Error::rpcINVALID_PARAMS, "ledgerHashMalformed"};
return RPC::Status{
RPC::Error::rpcINVALID_PARAMS, "ledgerHashMalformed"};
lgrInfo = ctx.backend->fetchLedgerByHash(ledgerHash);
}
else if (!indexValue.is_null())
{
@@ -155,15 +222,14 @@ ledgerInfoFromRequest(RPC::Context const& ctx)
else if (!indexValue.is_string() && indexValue.is_int64())
ledgerSequence = indexValue.as_int64();
else
return RPC::Status{RPC::Error::rpcINVALID_PARAMS, "ledgerIndexMalformed"};
return RPC::Status{
RPC::Error::rpcINVALID_PARAMS, "ledgerIndexMalformed"};
lgrInfo =
ctx.backend->fetchLedgerBySequence(ledgerSequence);
lgrInfo = ctx.backend->fetchLedgerBySequence(ledgerSequence);
}
else
{
lgrInfo =
ctx.backend->fetchLedgerBySequence(ctx.range.maxSequence);
lgrInfo = ctx.backend->fetchLedgerBySequence(ctx.range.maxSequence);
}
if (!lgrInfo)
@@ -297,13 +363,15 @@ keypairFromRequst(boost::json::object const& request)
}
if (count == 0)
return RPC::Status{RPC::Error::rpcINVALID_PARAMS, "missing field secret"};
return RPC::Status{
RPC::Error::rpcINVALID_PARAMS, "missing field secret"};
if (count > 1)
{
return RPC::Status{RPC::Error::rpcINVALID_PARAMS,
"Exactly one of the following must be specified: "
" passphrase, secret, seed, or seed_hex"};
return RPC::Status{
RPC::Error::rpcINVALID_PARAMS,
"Exactly one of the following must be specified: "
" passphrase, secret, seed, or seed_hex"};
}
boost::optional<ripple::KeyType> keyType;
@@ -312,18 +380,20 @@ keypairFromRequst(boost::json::object const& request)
if (has_key_type)
{
if (!request.at("key_type").is_string())
return RPC::Status{RPC::Error::rpcINVALID_PARAMS, "keyTypeNotString"};
return RPC::Status{
RPC::Error::rpcINVALID_PARAMS, "keyTypeNotString"};
std::string key_type = request.at("key_type").as_string().c_str();
keyType = ripple::keyTypeFromString(key_type);
if (!keyType)
return RPC::Status{RPC::Error::rpcINVALID_PARAMS, "invalidFieldKeyType"};
return RPC::Status{
RPC::Error::rpcINVALID_PARAMS, "invalidFieldKeyType"};
if (secretType == "secret")
return RPC::Status{RPC::Error::rpcINVALID_PARAMS,
"The secret field is not allowed if key_type is used."};
return RPC::Status{
RPC::Error::rpcINVALID_PARAMS,
"The secret field is not allowed if key_type is used."};
}
// ripple-lib encodes seed used to generate an Ed25519 wallet in a
@@ -337,9 +407,11 @@ keypairFromRequst(boost::json::object const& request)
{
// If the user passed in an Ed25519 seed but *explicitly*
// requested another key type, return an error.
if (keyType.value_or(ripple::KeyType::ed25519) != ripple::KeyType::ed25519)
return RPC::Status{RPC::Error::rpcINVALID_PARAMS,
"Specified seed is for an Ed25519 wallet."};
if (keyType.value_or(ripple::KeyType::ed25519) !=
ripple::KeyType::ed25519)
return RPC::Status{
RPC::Error::rpcINVALID_PARAMS,
"Specified seed is for an Ed25519 wallet."};
keyType = ripple::KeyType::ed25519;
}
@@ -353,8 +425,9 @@ keypairFromRequst(boost::json::object const& request)
if (has_key_type)
{
if (!request.at(secretType).is_string())
return RPC::Status{RPC::Error::rpcINVALID_PARAMS,
"secret value must be string"};
return RPC::Status{
RPC::Error::rpcINVALID_PARAMS,
"secret value must be string"};
std::string key = request.at(secretType).as_string().c_str();
@@ -372,8 +445,9 @@ keypairFromRequst(boost::json::object const& request)
else
{
if (!request.at("secret").is_string())
return RPC::Status{RPC::Error::rpcINVALID_PARAMS,
"field secret should be a string"};
return RPC::Status{
RPC::Error::rpcINVALID_PARAMS,
"field secret should be a string"};
std::string secret = request.at("secret").as_string().c_str();
seed = ripple::parseGenericSeed(secret);
@@ -381,13 +455,15 @@ keypairFromRequst(boost::json::object const& request)
}
if (!seed)
return RPC::Status{RPC::Error::rpcBAD_SEED,
"Bad Seed: invalid field message secretType"};
return RPC::Status{
RPC::Error::rpcBAD_SEED,
"Bad Seed: invalid field message secretType"};
if (keyType != ripple::KeyType::secp256k1
&& keyType != ripple::KeyType::ed25519)
return RPC::Status{RPC::Error::rpcINVALID_PARAMS,
"keypairForSignature: invalid key type"};
if (keyType != ripple::KeyType::secp256k1 &&
keyType != ripple::KeyType::ed25519)
return RPC::Status{
RPC::Error::rpcINVALID_PARAMS,
"keypairForSignature: invalid key type"};
return generateKeyPair(*keyType, *seed);
}
@@ -498,7 +574,8 @@ xrpLiquid(
std::uint32_t const ownerCount = sle.getFieldU32(ripple::sfOwnerCount);
auto const reserve = backend.fetchFees(sequence)->accountReserve(ownerCount);
auto const reserve =
backend.fetchFees(sequence)->accountReserve(ownerCount);
auto const balance = sle.getFieldAmount(ripple::sfBalance);

View File

@@ -2,15 +2,15 @@
#ifndef XRPL_REPORTING_RPCHELPERS_H_INCLUDED
#define XRPL_REPORTING_RPCHELPERS_H_INCLUDED
#include <ripple/protocol/STLedgerEntry.h>
#include <ripple/app/ledger/Ledger.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/jss.h>
#include <ripple/protocol/STLedgerEntry.h>
#include <ripple/protocol/STTx.h>
#include <ripple/protocol/jss.h>
#include <boost/json.hpp>
#include <handlers/Status.h>
#include <handlers/Context.h>
#include <backend/BackendInterface.h>
#include <handlers/Context.h>
#include <handlers/Status.h>
std::optional<ripple::AccountID>
accountFromStringStrict(std::string const& account);
@@ -27,6 +27,9 @@ deserializeTxPlusMeta(
Backend::TransactionAndMetadata const& blobs,
std::uint32_t seq);
std::pair<boost::json::object, boost::json::object>
toExpandedJson(Backend::TransactionAndMetadata const& blobs);
boost::json::object
toJson(ripple::STBase const& obj);

View File

@@ -194,11 +194,10 @@ doAccountTx(Context const& context)
if (!binary)
{
auto [txn, meta] = deserializeTxPlusMeta(txnPlusMeta);
obj["meta"] = toJson(*meta);
obj["tx"] = toJson(*txn);
auto [txn, meta] = toExpandedJson(txnPlusMeta);
obj["meta"] = meta;
obj["tx"] = txn;
obj["tx"].as_object()["ledger_index"] = txnPlusMeta.ledgerSequence;
obj["tx"].as_object()["inLedger"] = txnPlusMeta.ledgerSequence;
}
else
{

View File

@@ -1,9 +1,8 @@
#include <handlers/methods/Ledger.h>
#include <handlers/RPCHelpers.h>
#include <backend/BackendInterface.h>
#include <handlers/RPCHelpers.h>
#include <handlers/methods/Ledger.h>
namespace RPC
{
namespace RPC {
Result
doLedger(Context const& context)
@@ -12,27 +11,27 @@ doLedger(Context const& context)
boost::json::object response = {};
bool binary = false;
if(params.contains("binary"))
if (params.contains("binary"))
{
if(!params.at("binary").is_bool())
if (!params.at("binary").is_bool())
return Status{Error::rpcINVALID_PARAMS, "binaryFlagNotBool"};
binary = params.at("binary").as_bool();
}
bool transactions = false;
if(params.contains("transactions"))
if (params.contains("transactions"))
{
if(!params.at("transactions").is_bool())
if (!params.at("transactions").is_bool())
return Status{Error::rpcINVALID_PARAMS, "transactionsFlagNotBool"};
transactions = params.at("transactions").as_bool();
}
bool expand = false;
if(params.contains("expand"))
if (params.contains("expand"))
{
if(!params.at("expand").is_bool())
if (!params.at("expand").is_bool())
return Status{Error::rpcINVALID_PARAMS, "expandFlagNotBool"};
expand = params.at("expand").as_bool();
@@ -55,7 +54,8 @@ doLedger(Context const& context)
header["account_hash"] = ripple::strHex(lgrInfo.accountHash);
header["close_flags"] = lgrInfo.closeFlags;
header["close_time"] = lgrInfo.closeTime.time_since_epoch().count();
header["close_time_human"] = ripple::to_string(lgrInfo.closeTime);;
header["close_time_human"] = ripple::to_string(lgrInfo.closeTime);
;
header["close_time_resolution"] = lgrInfo.closeTimeResolution.count();
header["closed"] = true;
header["hash"] = ripple::strHex(lgrInfo.hash);
@@ -69,6 +69,7 @@ doLedger(Context const& context)
header["total_coins"] = ripple::to_string(lgrInfo.drops);
header["transaction_hash"] = ripple::strHex(lgrInfo.txHash);
}
header["closed"] = true;
if (transactions)
{
@@ -76,7 +77,8 @@ doLedger(Context const& context)
boost::json::array& jsonTxs = header.at("transactions").as_array();
if (expand)
{
auto txns = context.backend->fetchAllTransactionsInLedger(lgrInfo.seq);
auto txns =
context.backend->fetchAllTransactionsInLedger(lgrInfo.seq);
std::transform(
std::move_iterator(txns.begin()),
@@ -86,16 +88,16 @@ doLedger(Context const& context)
boost::json::object entry;
if (!binary)
{
auto [sttx, meta] = deserializeTxPlusMeta(obj);
entry = toJson(*sttx);
entry["metaData"] = toJson(*meta);
auto [txn, meta] = toExpandedJson(obj);
entry = txn;
entry["metaData"] = meta;
}
else
{
entry["tx_blob"] = ripple::strHex(obj.transaction);
entry["meta"] = ripple::strHex(obj.metadata);
}
entry["ledger_sequence"] = obj.ledgerSequence;
entry["ledger_index"] = obj.ledgerSequence;
return entry;
});
}
@@ -120,4 +122,4 @@ doLedger(Context const& context)
return response;
}
}
} // namespace RPC

View File

@@ -17,13 +17,12 @@
*/
//==============================================================================
#include <handlers/RPCHelpers.h>
#include <handlers/methods/Transaction.h>
#include <backend/BackendInterface.h>
#include <backend/Pg.h>
#include <handlers/RPCHelpers.h>
#include <handlers/methods/Transaction.h>
namespace RPC
{
namespace RPC {
// {
// transaction: <hex>
@@ -46,9 +45,9 @@ doTx(Context const& context)
return Status{Error::rpcINVALID_PARAMS, "malformedTransaction"};
bool binary = false;
if(request.contains("binary"))
if (request.contains("binary"))
{
if(!request.at("binary").is_bool())
if (!request.at("binary").is_bool())
return Status{Error::rpcINVALID_PARAMS, "binaryFlagNotBool"};
binary = request.at("binary").as_bool();
@@ -64,9 +63,10 @@ doTx(Context const& context)
if (!binary)
{
auto [sttx, meta] = deserializeTxPlusMeta(dbResponse.value());
response = toJson(*sttx);
response["meta"] = toJson(*meta);
auto [txn, meta] = toExpandedJson(*dbResponse);
response = txn;
response["meta"] = meta;
response["ledger_index"] = dbResponse->ledgerSequence;
}
else
{
@@ -77,4 +77,4 @@ doTx(Context const& context)
return response;
}
} // namespace RPC
} // namespace RPC