gRPC support for account_tx and tx

- Add support for all transaction types and ledger object types to gRPC
  implementation of tx and account_tx.

- Create common handlers for tx and account_tx.

- Remove mutex and abort() from gRPC server. JobQueue is stopped before
  gRPC server, with all coroutines executed to completion, so no need for
  synchronization.
This commit is contained in:
CJ Cobb
2020-02-04 12:31:17 -08:00
committed by Mike Ellery
parent acf4b78892
commit e7ce3909d2
57 changed files with 7498 additions and 2106 deletions

View File

@@ -39,43 +39,24 @@ namespace RPC {
would be calculated even when not needed, and in some circumstances they are
not trivial to compute.
GetFix1623Enabled is a callable that returns a bool
GetLedgerIndex is a callable that returns a LedgerIndex
GetCloseTime is a callable that returns a
boost::optional<NetClock::time_point>
*/
template<class GetFix1623Enabled, class GetLedgerIndex, class GetCloseTime>
void
insertDeliveredAmount(
Json::Value& meta,
GetFix1623Enabled const& getFix1623Enabled,
template <class GetLedgerIndex, class GetCloseTime>
std::optional<STAmount>
getDeliveredAmount(
GetLedgerIndex const& getLedgerIndex,
GetCloseTime const& getCloseTime,
std::shared_ptr<STTx const> serializedTx,
std::shared_ptr<STTx const> const& serializedTx,
TxMeta const& transactionMeta)
{
{
TxType const tt{serializedTx->getTxnType()};
if (tt != ttPAYMENT &&
tt != ttCHECK_CASH &&
tt != ttACCOUNT_DELETE)
return;
if (tt == ttCHECK_CASH &&
!getFix1623Enabled())
return;
}
// if the transaction failed nothing could have been delivered.
if (transactionMeta.getResultTER() != tesSUCCESS)
return;
if (!serializedTx)
return {};
if (transactionMeta.hasDeliveredAmount())
{
meta[jss::delivered_amount] =
transactionMeta.getDeliveredAmount()
.getJson(JsonOptions::include_date);
return;
return transactionMeta.getDeliveredAmount();
}
if (serializedTx->isFieldPresent(sfAmount))
@@ -93,156 +74,161 @@ insertDeliveredAmount(
if (getLedgerIndex() >= 4594095 ||
getCloseTime() > NetClock::time_point{446000000s})
{
meta[jss::delivered_amount] =
serializedTx->getFieldAmount(sfAmount)
.getJson(JsonOptions::include_date);
return;
return serializedTx->getFieldAmount(sfAmount);
}
}
// report "unavailable" which cannot be parsed into a sensible amount.
meta[jss::delivered_amount] = Json::Value("unavailable");
return {};
}
// Returns true if transaction meta could contain a delivered amount field,
// based on transaction type, transaction result and whether fix1623 is enabled
template <class GetFix1623Enabled>
bool
canHaveDeliveredAmountHelp(
GetFix1623Enabled const& getFix1623Enabled,
std::shared_ptr<STTx const> const& serializedTx,
TxMeta const& transactionMeta)
{
if (!serializedTx)
return false;
{
TxType const tt{serializedTx->getTxnType()};
if (tt != ttPAYMENT && tt != ttCHECK_CASH && tt != ttACCOUNT_DELETE)
return false;
if (tt == ttCHECK_CASH && !getFix1623Enabled())
return false;
}
// if the transaction failed nothing could have been delivered.
if (transactionMeta.getResultTER() != tesSUCCESS)
return false;
return true;
}
// Returns true if transaction meta could contain a delivered amount field,
// based on transaction type, transaction result and whether fix1623 is enabled
bool
canHaveDeliveredAmount(
RPC::Context const& context,
std::shared_ptr<STTx const> const& serializedTx,
TxMeta const& transactionMeta)
{
// These lambdas are used to compute the values lazily
auto const getFix1623Enabled = [&context]() -> bool {
auto const view = context.app.openLedger().current();
if (!view)
return false;
return view->rules().enabled(fix1623);
};
return canHaveDeliveredAmountHelp(
getFix1623Enabled, serializedTx, transactionMeta);
}
void
insertDeliveredAmount(
Json::Value& meta,
ReadView const& ledger,
std::shared_ptr<STTx const> serializedTx,
std::shared_ptr<STTx const> const& serializedTx,
TxMeta const& transactionMeta)
{
if (!serializedTx)
return;
auto const info = ledger.info();
auto const getFix1623Enabled = [&ledger] {
return ledger.rules().enabled(fix1623);
};
auto const getLedgerIndex = [&info] {
return info.seq;
};
auto const getCloseTime = [&info] {
return info.closeTime;
};
insertDeliveredAmount(
meta,
getFix1623Enabled,
getLedgerIndex,
getCloseTime,
std::move(serializedTx),
transactionMeta);
if (canHaveDeliveredAmountHelp(
getFix1623Enabled, serializedTx, transactionMeta))
{
auto const getLedgerIndex = [&info] { return info.seq; };
auto const getCloseTime = [&info] { return info.closeTime; };
auto amt = getDeliveredAmount(
getLedgerIndex,
getCloseTime,
std::move(serializedTx),
transactionMeta);
if (amt)
{
meta[jss::delivered_amount] =
amt->getJson(JsonOptions::include_date);
}
else
{
// report "unavailable" which cannot be parsed into a sensible
// amount.
meta[jss::delivered_amount] = Json::Value("unavailable");
}
}
}
template <class GetLedgerIndex>
std::optional<STAmount>
getDeliveredAmount(
RPC::Context const& context,
std::shared_ptr<STTx const> const& serializedTx,
TxMeta const& transactionMeta,
GetLedgerIndex const& getLedgerIndex)
{
if (canHaveDeliveredAmount(context, serializedTx, transactionMeta))
{
auto const getCloseTime =
[&context,
&getLedgerIndex]() -> boost::optional<NetClock::time_point> {
return context.ledgerMaster.getCloseTimeBySeq(getLedgerIndex());
};
return getDeliveredAmount(
getLedgerIndex,
getCloseTime,
std::move(serializedTx),
transactionMeta);
}
return {};
}
std::optional<STAmount>
getDeliveredAmount(
RPC::Context const& context,
std::shared_ptr<STTx const> const& serializedTx,
TxMeta const& transactionMeta,
LedgerIndex const& ledgerIndex)
{
return getDeliveredAmount(
context, serializedTx, transactionMeta, [&ledgerIndex]() {
return ledgerIndex;
});
}
void
insertDeliveredAmount(
Json::Value& meta,
RPC::JsonContext& context,
std::shared_ptr<Transaction> transaction,
RPC::JsonContext const& context,
std::shared_ptr<Transaction> const& transaction,
TxMeta const& transactionMeta)
{
if (!transaction)
return;
auto const serializedTx = transaction->getSTransaction ();
if (! serializedTx)
return;
// These lambdas are used to compute the values lazily
auto const getFix1623Enabled = [&context]() -> bool {
auto const view = context.app.openLedger().current();
if (!view)
return false;
return view->rules().enabled(fix1623);
};
auto const getLedgerIndex = [&transaction]() -> LedgerIndex {
return transaction->getLedger();
};
auto const getCloseTime =
[&context, &transaction]() -> boost::optional<NetClock::time_point> {
return context.ledgerMaster.getCloseTimeBySeq(transaction->getLedger());
};
insertDeliveredAmount(
meta,
getFix1623Enabled,
getLedgerIndex,
getCloseTime,
std::move(serializedTx),
transactionMeta);
}
// TODO get rid of the code duplication between this function and the preceding
// function
void
insertDeliveredAmount(
rpc::v1::CurrencyAmount& proto,
RPC::Context& context,
std::shared_ptr<Transaction> transaction,
TxMeta const& transactionMeta)
{
if (!transaction)
return;
auto const serializedTx = transaction->getSTransaction();
if (!serializedTx)
return;
// These lambdas are used to compute the values lazily
auto const getFix1623Enabled = [&context]() -> bool {
auto const view = context.app.openLedger().current();
if (!view)
return false;
return view->rules().enabled(fix1623);
};
auto const getLedgerIndex = [&transaction]() -> LedgerIndex {
return transaction->getLedger();
};
auto const getCloseTime =
[&context, &transaction]() -> boost::optional<NetClock::time_point> {
return context.ledgerMaster.getCloseTimeBySeq(transaction->getLedger());
};
if (canHaveDeliveredAmount(context, serializedTx, transactionMeta))
{
TxType const tt{serializedTx->getTxnType()};
if (tt != ttPAYMENT &&
tt != ttCHECK_CASH &&
tt != ttACCOUNT_DELETE)
return;
auto amt = getDeliveredAmount(
context, serializedTx, transactionMeta, [&transaction]() {
return transaction->getLedger();
});
if (tt == ttCHECK_CASH &&
!getFix1623Enabled())
return;
}
// if the transaction failed nothing could have been delivered.
if (transactionMeta.getResultTER() != tesSUCCESS)
return;
if (transactionMeta.hasDeliveredAmount())
{
populateAmount(proto, transactionMeta.getDeliveredAmount());
return;
}
if (serializedTx->isFieldPresent(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 (getLedgerIndex() >= 4594095 ||
getCloseTime() > NetClock::time_point{446000000s})
if (amt)
{
populateAmount(proto, serializedTx->getFieldAmount(sfAmount));
return;
meta[jss::delivered_amount] =
amt->getJson(JsonOptions::include_date);
}
else
{
// report "unavailable" which cannot be parsed into a sensible
// amount.
meta[jss::delivered_amount] = Json::Value("unavailable");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,87 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2020 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_RPC_GRPCHELPERS_H_INCLUDED
#define RIPPLE_RPC_GRPCHELPERS_H_INCLUDED
#include "org/xrpl/rpc/v1/get_account_info.pb.h"
#include "org/xrpl/rpc/v1/ledger_objects.pb.h"
#include "org/xrpl/rpc/v1/meta.pb.h"
#include "org/xrpl/rpc/v1/transaction.pb.h"
#include <ripple/app/misc/TxQ.h>
#include <ripple/ledger/TxMeta.h>
#include <ripple/protocol/Protocol.h>
#include <ripple/protocol/STAmount.h>
#include <ripple/protocol/STTx.h>
#include <functional>
namespace ripple {
namespace RPC {
void
convert(org::xrpl::rpc::v1::Meta& to, std::shared_ptr<TxMeta> const& from);
void
convert(
org::xrpl::rpc::v1::QueueData& to,
std::map<TxSeq, TxQ::AccountTxDetails const> const& from);
void
convert(
org::xrpl::rpc::v1::Transaction& to,
std::shared_ptr<STTx const> const& from);
void
convert(org::xrpl::rpc::v1::TransactionResult& to, TER from);
void
convert(org::xrpl::rpc::v1::AccountRoot& to, STObject const& from);
void
convert(org::xrpl::rpc::v1::SignerList& to, STObject const& from);
template <class T>
void
convert(T& to, STAmount const& from)
{
if (from.native())
{
to.mutable_value()->mutable_xrp_amount()->set_drops(from.xrp().drops());
}
else
{
Issue const& issue = from.issue();
org::xrpl::rpc::v1::IssuedCurrencyAmount* issued =
to.mutable_value()->mutable_issued_currency_amount();
issued->mutable_currency()->set_name(to_string(issue.currency));
issued->mutable_currency()->set_code(
issue.currency.data(), Currency::size());
issued->mutable_issuer()->set_address(toBase58(issue.account));
issued->set_value(to_string(from.iou()));
}
}
} // namespace RPC
} // namespace ripple
#endif

View File

@@ -65,7 +65,7 @@ Handler const handlerArray[] {
{ "account_channels", byRef (&doAccountChannels), Role::USER, NO_CONDITION },
{ "account_objects", byRef (&doAccountObjects), Role::USER, NO_CONDITION },
{ "account_offers", byRef (&doAccountOffers), Role::USER, NO_CONDITION },
{ "account_tx", byRef (&doAccountTxSwitch), Role::USER, NO_CONDITION },
{ "account_tx", byRef (&doAccountTxJson), Role::USER, NO_CONDITION },
{ "blacklist", byRef (&doBlackList), Role::ADMIN, NO_CONDITION },
{ "book_offers", byRef (&doBookOffers), Role::USER, NO_CONDITION },
{ "can_delete", byRef (&doCanDelete), Role::ADMIN, NO_CONDITION },
@@ -112,7 +112,7 @@ Handler const handlerArray[] {
{ "crawl_shards", byRef (&doCrawlShards), Role::ADMIN, NO_CONDITION },
{ "stop", byRef (&doStop), Role::ADMIN, NO_CONDITION },
{ "transaction_entry", byRef (&doTransactionEntry), Role::USER, NO_CONDITION },
{ "tx", byRef (&doTx), Role::USER, NEEDS_NETWORK_CONNECTION },
{ "tx", byRef (&doTxJson), Role::USER, NEEDS_NETWORK_CONNECTION },
{ "tx_history", byRef (&doTxHistory), Role::USER, NO_CONDITION },
{ "unl_list", byRef (&doUnlList), Role::ADMIN, NO_CONDITION },
{ "validation_create", byRef (&doValidationCreate), Role::ADMIN, NO_CONDITION },

View File

@@ -29,6 +29,8 @@
#include <ripple/rpc/impl/RPCHelpers.h>
#include <boost/algorithm/string/case_conv.hpp>
#include <ripple/rpc/impl/GRPCHelpers.h>
namespace ripple {
namespace RPC {
@@ -199,12 +201,10 @@ template <class T>
Status
ledgerFromRequest(T& ledger, JsonContext& context)
{
static auto const minSequenceGap = 10;
ledger.reset();
auto& params = context.params;
auto& ledgerMaster = context.ledgerMaster;
auto indexValue = params[jss::ledger_index];
auto hashValue = params[jss::ledger_hash];
@@ -225,74 +225,32 @@ ledgerFromRequest(T& ledger, JsonContext& context)
return {rpcINVALID_PARAMS, "ledgerHashNotString"};
uint256 ledgerHash;
if (! ledgerHash.SetHex (hashValue.asString ()))
if(!ledgerHash.SetHex (hashValue.asString ()))
return {rpcINVALID_PARAMS, "ledgerHashMalformed"};
ledger = ledgerMaster.getLedgerByHash (ledgerHash);
if (ledger == nullptr)
return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
return getLedger(ledger, ledgerHash, context);
}
else if (indexValue.isNumeric())
{
ledger = ledgerMaster.getLedgerBySeq (indexValue.asInt ());
if (ledger == nullptr)
{
auto cur = ledgerMaster.getCurrentLedger();
if (cur->info().seq == indexValue.asInt())
ledger = cur;
}
if (ledger == nullptr)
return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
if (ledger->info().seq > ledgerMaster.getValidLedgerIndex() &&
isValidatedOld(ledgerMaster, context.app.config().standalone()))
{
ledger.reset();
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
}
return getLedger(ledger, indexValue.asInt(),context);
}
else
{
if (isValidatedOld (ledgerMaster, context.app.config().standalone()))
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
auto const index = indexValue.asString ();
if (index == "validated")
{
ledger = ledgerMaster.getValidatedLedger ();
if (ledger == nullptr)
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
assert (! ledger->open());
return getLedger(ledger, LedgerShortcut::VALIDATED, context);
}
else
{
if (index.empty () || index == "current")
{
ledger = ledgerMaster.getCurrentLedger ();
assert (ledger->open());
}
return getLedger(ledger, LedgerShortcut::CURRENT, context);
else if (index == "closed")
{
ledger = ledgerMaster.getClosedLedger ();
assert (! ledger->open());
}
return getLedger(ledger, LedgerShortcut::CLOSED, context);
else
{
return {rpcINVALID_PARAMS, "ledgerIndexMalformed"};
}
if (ledger == nullptr)
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
if (ledger->info().seq + minSequenceGap <
ledgerMaster.getValidLedgerIndex ())
{
ledger.reset ();
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
}
}
}
@@ -304,88 +262,49 @@ template <class T>
Status
ledgerFromRequest(
T& ledger,
GRPCContext<rpc::v1::GetAccountInfoRequest>& context)
GRPCContext<org::xrpl::rpc::v1::GetAccountInfoRequest>& context)
{
static auto const minSequenceGap = 10;
ledger.reset();
rpc::v1::GetAccountInfoRequest& request = context.params;
auto& ledgerMaster = context.ledgerMaster;
org::xrpl::rpc::v1::GetAccountInfoRequest& request = context.params;
using LedgerCase = rpc::v1::LedgerSpecifier::LedgerCase;
using LedgerCase = org::xrpl::rpc::v1::LedgerSpecifier::LedgerCase;
LedgerCase ledgerCase = request.ledger().ledger_case();
if (ledgerCase == LedgerCase::kHash)
switch (ledgerCase)
{
uint256 ledgerHash = uint256::fromVoid(request.ledger().hash().data());
if (ledgerHash.size() != request.ledger().hash().size())
return {rpcINVALID_PARAMS, "ledgerHashMalformed"};
ledger = ledgerMaster.getLedgerByHash(ledgerHash);
if (ledger == nullptr)
return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
}
else if (ledgerCase == LedgerCase::kSequence)
{
ledger = ledgerMaster.getLedgerBySeq(request.ledger().sequence());
if (ledger == nullptr)
case LedgerCase::kHash:
{
auto cur = ledgerMaster.getCurrentLedger();
if (cur->info().seq == request.ledger().sequence())
ledger = cur;
uint256 ledgerHash =
uint256::fromVoid(request.ledger().hash().data());
return getLedger(ledger, ledgerHash, context);
}
if (ledger == nullptr)
return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
if (ledger->info().seq > ledgerMaster.getValidLedgerIndex() &&
isValidatedOld(ledgerMaster, context.app.config().standalone()))
case LedgerCase::kSequence:
return getLedger(ledger, request.ledger().sequence(), context);
case LedgerCase::kShortcut:
[[fallthrough]];
case LedgerCase::LEDGER_NOT_SET:
{
ledger.reset();
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
}
}
else if (
ledgerCase == LedgerCase::kShortcut ||
ledgerCase == LedgerCase::LEDGER_NOT_SET)
{
if (isValidatedOld(ledgerMaster, context.app.config().standalone()))
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
auto const shortcut = request.ledger().shortcut();
if (shortcut == rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED)
{
ledger = ledgerMaster.getValidatedLedger();
if (ledger == nullptr)
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
assert(!ledger->open());
}
else
{
// note, if unspecified, defaults to current ledger
if (shortcut == rpc::v1::LedgerSpecifier::SHORTCUT_UNSPECIFIED ||
shortcut == rpc::v1::LedgerSpecifier::SHORTCUT_CURRENT)
auto const shortcut = request.ledger().shortcut();
if (shortcut ==
org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED)
return getLedger(ledger, LedgerShortcut::VALIDATED, context);
else
{
ledger = ledgerMaster.getCurrentLedger();
assert(ledger->open());
}
else if (shortcut == rpc::v1::LedgerSpecifier::SHORTCUT_CLOSED)
{
ledger = ledgerMaster.getClosedLedger();
assert(!ledger->open());
}
if (ledger == nullptr)
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
if (ledger->info().seq + minSequenceGap <
ledgerMaster.getValidLedgerIndex())
{
ledger.reset();
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
// note, if unspecified, defaults to current ledger
if (shortcut ==
org::xrpl::rpc::v1::LedgerSpecifier::
SHORTCUT_UNSPECIFIED ||
shortcut ==
org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CURRENT)
{
return getLedger(ledger, LedgerShortcut::CURRENT, context);
}
else if (
shortcut ==
org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CLOSED)
{
return getLedger(ledger, LedgerShortcut::CLOSED, context);
}
}
}
}
@@ -397,7 +316,103 @@ ledgerFromRequest(
template Status
ledgerFromRequest<>(
std::shared_ptr<ReadView const>&,
GRPCContext<rpc::v1::GetAccountInfoRequest>&);
GRPCContext<org::xrpl::rpc::v1::GetAccountInfoRequest>&);
Status
getLedger(
std::shared_ptr<ReadView const>& ledger,
uint256 const& ledgerHash,
Context& context)
{
ledger = context.ledgerMaster.getLedgerByHash(ledgerHash);
if (ledger == nullptr)
return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
return Status::OK;
}
template <class T>
Status
getLedger(T& ledger, uint32_t ledgerIndex, Context& context)
{
ledger = context.ledgerMaster.getLedgerBySeq(ledgerIndex);
if (ledger == nullptr)
{
auto cur = context.ledgerMaster.getCurrentLedger();
if (cur->info().seq == ledgerIndex)
{
ledger = cur;
}
}
if (ledger == nullptr)
return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
if (ledger->info().seq > context.ledgerMaster.getValidLedgerIndex() &&
isValidatedOld(context.ledgerMaster, context.app.config().standalone()))
{
ledger.reset();
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
}
return Status::OK;
}
template <class T>
Status
getLedger(T& ledger, LedgerShortcut shortcut, Context& context)
{
if (isValidatedOld (context.ledgerMaster, context.app.config().standalone()))
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
if (shortcut == LedgerShortcut::VALIDATED)
{
ledger = context.ledgerMaster.getValidatedLedger ();
if (ledger == nullptr)
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
assert (! ledger->open());
}
else
{
if (shortcut == LedgerShortcut::CURRENT)
{
ledger = context.ledgerMaster.getCurrentLedger ();
assert (ledger->open());
}
else if (shortcut == LedgerShortcut::CLOSED)
{
ledger = context.ledgerMaster.getClosedLedger ();
assert (! ledger->open());
}
else
{
return {rpcINVALID_PARAMS, "ledgerIndexMalformed"};
}
if (ledger == nullptr)
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
static auto const minSequenceGap = 10;
if (ledger->info().seq + minSequenceGap <
context.ledgerMaster.getValidLedgerIndex ())
{
ledger.reset ();
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
}
}
return Status::OK;
}
//Explicit instantiaion of above three functions
template Status
getLedger<>(std::shared_ptr<ReadView const>&,
uint32_t, Context&);
template Status
getLedger<>(std::shared_ptr<ReadView const>&,
LedgerShortcut shortcut, Context&);
bool
isValidated(LedgerMaster& ledgerMaster, ReadView const& ledger,
@@ -823,672 +838,6 @@ chooseLedgerEntryType(Json::Value const& params)
return result;
}
void
populateAccountRoot(rpc::v1::AccountRoot& proto, STObject const& obj)
{
if (obj.isFieldPresent(sfAccount))
{
AccountID account = obj.getAccountID(sfAccount);
proto.mutable_account()->set_address(toBase58(account));
}
if (obj.isFieldPresent(sfBalance))
{
STAmount amount = obj.getFieldAmount(sfBalance);
proto.mutable_balance()->set_drops(amount.xrp().drops());
}
if (obj.isFieldPresent(sfSequence))
{
proto.set_sequence(obj.getFieldU32(sfSequence));
}
if (obj.isFieldPresent(sfFlags))
{
proto.set_flags(obj.getFieldU32(sfFlags));
}
if (obj.isFieldPresent(sfOwnerCount))
{
proto.set_owner_count(obj.getFieldU32(sfOwnerCount));
}
if (obj.isFieldPresent(sfPreviousTxnID))
{
auto field = obj.getFieldH256(sfPreviousTxnID);
proto.set_previous_transaction_id(field.data(), field.size());
}
if (obj.isFieldPresent(sfPreviousTxnLgrSeq))
{
proto.set_previous_transaction_ledger_sequence(
obj.getFieldU32(sfPreviousTxnLgrSeq));
}
if (obj.isFieldPresent(sfAccountTxnID))
{
auto field = obj.getFieldH256(sfAccountTxnID);
proto.set_account_transaction_id(field.data(), field.size());
}
if (obj.isFieldPresent(sfDomain))
{
auto field = obj.getFieldH256(sfDomain);
proto.set_domain(field.data(), field.size());
}
if (obj.isFieldPresent(sfEmailHash))
{
auto field = obj.getFieldH128(sfEmailHash);
proto.set_email_hash(field.data(), field.size());
}
if (obj.isFieldPresent(sfMessageKey))
{
auto field = obj.getFieldVL(sfMessageKey);
proto.set_message_key(field.data(), field.size());
}
if (obj.isFieldPresent(sfRegularKey))
{
proto.set_regular_key(toBase58(obj.getAccountID(sfRegularKey)));
}
if (obj.isFieldPresent(sfTickSize))
{
proto.set_tick_size(obj.getFieldU8(sfTickSize));
}
if (obj.isFieldPresent(sfTransferRate))
{
proto.set_transfer_rate(obj.getFieldU32(sfTransferRate));
}
}
void
populateRippleState(rpc::v1::RippleState& proto, STObject const& obj)
{
if (obj.isFieldPresent(sfBalance))
{
STAmount amount = obj.getFieldAmount(sfBalance);
populateAmount(*proto.mutable_balance(), amount);
}
if (obj.isFieldPresent(sfFlags))
{
proto.set_flags(obj.getFieldU32(sfFlags));
}
if (obj.isFieldPresent(sfLowLimit))
{
STAmount amount = obj.getFieldAmount(sfLowLimit);
populateAmount(*proto.mutable_low_limit(), amount);
}
if (obj.isFieldPresent(sfHighLimit))
{
STAmount amount = obj.getFieldAmount(sfHighLimit);
populateAmount(*proto.mutable_high_limit(), amount);
}
if (obj.isFieldPresent(sfLowNode))
{
proto.set_low_node(obj.getFieldU64(sfLowNode));
}
if (obj.isFieldPresent(sfHighNode))
{
proto.set_high_node(obj.getFieldU64(sfHighNode));
}
if (obj.isFieldPresent(sfLowQualityIn))
{
proto.set_low_quality_in(obj.getFieldU32(sfLowQualityIn));
}
if (obj.isFieldPresent(sfLowQualityOut))
{
proto.set_low_quality_out(obj.getFieldU32(sfLowQualityOut));
}
if (obj.isFieldPresent(sfHighQualityIn))
{
proto.set_high_quality_in(obj.getFieldU32(sfHighQualityIn));
}
if (obj.isFieldPresent(sfHighQualityOut))
{
proto.set_high_quality_out(obj.getFieldU32(sfHighQualityOut));
}
}
void
populateOffer(rpc::v1::Offer& proto, STObject const& obj)
{
if (obj.isFieldPresent(sfAccount))
{
AccountID account = obj.getAccountID(sfAccount);
proto.set_account(toBase58(account));
}
if (obj.isFieldPresent(sfSequence))
{
proto.set_sequence(obj.getFieldU32(sfSequence));
}
if (obj.isFieldPresent(sfFlags))
{
proto.set_flags(obj.getFieldU32(sfFlags));
}
if (obj.isFieldPresent(sfTakerPays))
{
STAmount amount = obj.getFieldAmount(sfTakerPays);
populateAmount(*proto.mutable_taker_pays(), amount);
}
if (obj.isFieldPresent(sfTakerGets))
{
STAmount amount = obj.getFieldAmount(sfTakerGets);
populateAmount(*proto.mutable_taker_gets(), amount);
}
if (obj.isFieldPresent(sfBookDirectory))
{
auto field = obj.getFieldVL(sfBookDirectory);
proto.set_book_directory(field.data(), field.size());
}
if (obj.isFieldPresent(sfBookNode))
{
proto.set_book_node(obj.getFieldU64(sfBookNode));
}
if (obj.isFieldPresent(sfExpiration))
{
proto.set_expiration(obj.getFieldU32(sfExpiration));
}
}
void
populateSignerList(rpc::v1::SignerList& proto, STObject const& obj)
{
proto.set_flags(obj.getFieldU32(sfFlags));
auto prevTxnID = obj.getFieldH256(sfPreviousTxnID);
proto.set_previous_txn_id(prevTxnID.data(), prevTxnID.size());
proto.set_previous_transaction_ledger_sequence(
obj.getFieldU32(sfPreviousTxnLgrSeq));
proto.set_owner_node(obj.getFieldU64(sfOwnerNode));
proto.set_signer_list_id(obj.getFieldU32(sfSignerListID));
proto.set_signer_quorum(obj.getFieldU32(sfSignerQuorum));
STArray const& signerEntries = obj.getFieldArray(sfSignerEntries);
for (auto it = signerEntries.begin(); it != signerEntries.end(); ++it)
{
rpc::v1::SignerEntry& signerEntryProto = *proto.add_signer_entries();
signerEntryProto.mutable_account()->set_address(
toBase58(it->getAccountID(sfAccount)));
signerEntryProto.set_signer_weight(it->getFieldU16(sfSignerWeight));
}
}
void
populateQueueData(
rpc::v1::QueueData& proto,
std::map<TxSeq, TxQ::AccountTxDetails const> const& txs)
{
if (!txs.empty())
{
proto.set_txn_count(txs.size());
proto.set_lowest_sequence(txs.begin()->first);
proto.set_highest_sequence(txs.rbegin()->first);
boost::optional<bool> anyAuthChanged(false);
boost::optional<XRPAmount> totalSpend(0);
for (auto const& [txSeq, txDetails] : txs)
{
rpc::v1::QueuedTransaction& qt = *proto.add_transactions();
qt.set_sequence(txSeq);
qt.set_fee_level(txDetails.feeLevel.fee());
if (txDetails.lastValid)
qt.set_last_ledger_sequence(*txDetails.lastValid);
if (txDetails.consequences)
{
qt.mutable_fee()->set_drops(
txDetails.consequences->fee.drops());
auto spend = txDetails.consequences->potentialSpend +
txDetails.consequences->fee;
qt.mutable_max_spend_drops()->set_drops(spend.drops());
if (totalSpend)
*totalSpend += spend;
auto authChanged =
txDetails.consequences->category == TxConsequences::blocker;
if (authChanged)
anyAuthChanged.emplace(authChanged);
qt.set_auth_change(authChanged);
}
else
{
if (anyAuthChanged && !*anyAuthChanged)
anyAuthChanged.reset();
totalSpend.reset();
}
}
if (anyAuthChanged)
proto.set_auth_change_queued(*anyAuthChanged);
if (totalSpend)
proto.mutable_max_spend_drops_total()->set_drops(
(*totalSpend).drops());
}
}
void
populateDirectoryNode(rpc::v1::DirectoryNode& proto, STObject const& obj)
{
if (obj.isFieldPresent(sfOwner))
{
AccountID ownerAccount = obj.getAccountID(sfAccount);
proto.set_owner(toBase58(ownerAccount));
}
if (obj.isFieldPresent(sfTakerPaysCurrency))
{
uint160 tpCurr = obj.getFieldH160(sfTakerPaysCurrency);
proto.mutable_taker_pays_currency()->set_code(
tpCurr.data(), tpCurr.size());
}
if (obj.isFieldPresent(sfTakerPaysIssuer))
{
uint160 tpIss = obj.getFieldH160(sfTakerPaysIssuer);
proto.set_taker_pays_issuer(tpIss.data(), tpIss.size());
}
if (obj.isFieldPresent(sfTakerGetsCurrency))
{
uint160 tgCurr = obj.getFieldH160(sfTakerGetsCurrency);
proto.mutable_taker_gets_currency()->set_code(
tgCurr.data(), tgCurr.size());
}
if (obj.isFieldPresent(sfTakerGetsIssuer))
{
uint160 tgIss = obj.getFieldH160(sfTakerGetsIssuer);
proto.set_taker_gets_issuer(tgIss.data(), tgIss.size());
}
if (obj.isFieldPresent(sfIndexes))
{
const STVector256& vec = obj.getFieldV256(sfIndexes);
for (size_t i = 0; i < vec.size(); ++i)
{
uint256 const& elt = vec[i];
proto.add_indexes(elt.data(), elt.size());
}
}
if (obj.isFieldPresent(sfRootIndex))
{
uint256 rootIndex = obj.getFieldH256(sfRootIndex);
proto.set_root_index(rootIndex.data(), rootIndex.size());
}
if (obj.isFieldPresent(sfIndexNext))
{
proto.set_index_next(obj.getFieldU64(sfIndexNext));
}
if (obj.isFieldPresent(sfIndexPrevious))
{
proto.set_index_previous(obj.getFieldU64(sfIndexPrevious));
}
}
void
populateLedgerEntryType(rpc::v1::AffectedNode& proto, std::uint16_t lgrType)
{
switch (lgrType)
{
case ltACCOUNT_ROOT:
proto.set_ledger_entry_type(
rpc::v1::LEDGER_ENTRY_TYPE_ACCOUNT_ROOT);
break;
case ltDIR_NODE:
proto.set_ledger_entry_type(
rpc::v1::LEDGER_ENTRY_TYPE_DIRECTORY_NODE);
break;
case ltRIPPLE_STATE:
proto.set_ledger_entry_type(
rpc::v1::LEDGER_ENTRY_TYPE_RIPPLE_STATE);
break;
case ltSIGNER_LIST:
proto.set_ledger_entry_type(rpc::v1::LEDGER_ENTRY_TYPE_SIGNER_LIST);
break;
case ltOFFER:
proto.set_ledger_entry_type(rpc::v1::LEDGER_ENTRY_TYPE_OFFER);
break;
case ltLEDGER_HASHES:
proto.set_ledger_entry_type(
rpc::v1::LEDGER_ENTRY_TYPE_LEDGER_HASHES);
break;
case ltAMENDMENTS:
proto.set_ledger_entry_type(rpc::v1::LEDGER_ENTRY_TYPE_AMENDMENTS);
break;
case ltFEE_SETTINGS:
proto.set_ledger_entry_type(
rpc::v1::LEDGER_ENTRY_TYPE_FEE_SETTINGS);
break;
case ltESCROW:
proto.set_ledger_entry_type(rpc::v1::LEDGER_ENTRY_TYPE_ESCROW);
break;
case ltPAYCHAN:
proto.set_ledger_entry_type(rpc::v1::LEDGER_ENTRY_TYPE_PAY_CHANNEL);
break;
case ltCHECK:
proto.set_ledger_entry_type(rpc::v1::LEDGER_ENTRY_TYPE_CHECK);
break;
case ltDEPOSIT_PREAUTH:
proto.set_ledger_entry_type(
rpc::v1::LEDGER_ENTRY_TYPE_DEPOSIT_PREAUTH);
break;
}
}
template <class T>
void
populateFields(T& proto, STObject const& obj, std::uint16_t type)
{
if (type == ltACCOUNT_ROOT)
{
RPC::populateAccountRoot(*proto.mutable_account_root(), obj);
}
else if (type == ltRIPPLE_STATE)
{
RPC::populateRippleState(*proto.mutable_ripple_state(), obj);
}
else if (type == ltOFFER)
{
RPC::populateOffer(*proto.mutable_offer(), obj);
}
else if (type == ltDIR_NODE)
{
RPC::populateDirectoryNode(*proto.mutable_directory_node(), obj);
}
else
{
// Ledger object not supported by protobuf/grpc yet
}
}
void
populateMeta(rpc::v1::Meta& proto, std::shared_ptr<TxMeta> txMeta)
{
proto.set_transaction_index(txMeta->getIndex());
populateTransactionResultType(
*proto.mutable_transaction_result(), txMeta->getResultTER());
proto.mutable_transaction_result()->set_result(
transToken(txMeta->getResultTER()));
STArray& nodes = txMeta->getNodes();
for (auto it = nodes.begin(); it != nodes.end(); ++it)
{
STObject& obj = *it;
rpc::v1::AffectedNode* node = proto.add_affected_nodes();
// ledger index
uint256 ledgerIndex = obj.getFieldH256(sfLedgerIndex);
node->set_ledger_index(ledgerIndex.data(), ledgerIndex.size());
// ledger entry type
std::uint16_t lgrType = obj.getFieldU16(sfLedgerEntryType);
populateLedgerEntryType(*node, lgrType);
// modified node
if (obj.getFName() == sfModifiedNode)
{
// final fields
if (obj.isFieldPresent(sfFinalFields))
{
STObject& finalFields =
obj.getField(sfFinalFields).downcast<STObject>();
rpc::v1::LedgerObject* finalFieldsProto =
node->mutable_modified_node()->mutable_final_fields();
populateFields(*finalFieldsProto, finalFields, lgrType);
}
// previous fields
if (obj.isFieldPresent(sfPreviousFields))
{
STObject& prevFields =
obj.getField(sfPreviousFields).downcast<STObject>();
rpc::v1::LedgerObject* prevFieldsProto =
node->mutable_modified_node()->mutable_previous_fields();
populateFields(*prevFieldsProto, prevFields, lgrType);
}
// prev txn id and prev txn ledger seq
uint256 prevTxnId = obj.getFieldH256(sfPreviousTxnID);
node->mutable_modified_node()->set_previous_transaction_id(
prevTxnId.data(), prevTxnId.size());
node->mutable_modified_node()
->set_previous_transaction_ledger_sequence(
obj.getFieldU32(sfPreviousTxnLgrSeq));
}
// created node
else if (obj.getFName() == sfCreatedNode)
{
// new fields
if (obj.isFieldPresent(sfNewFields))
{
STObject& newFields =
obj.getField(sfNewFields).downcast<STObject>();
rpc::v1::LedgerObject* newFieldsProto =
node->mutable_created_node()->mutable_new_fields();
populateFields(*newFieldsProto, newFields, lgrType);
}
}
// deleted node
else if (obj.getFName() == sfDeletedNode)
{
// final fields
if (obj.isFieldPresent(sfFinalFields))
{
STObject& finalFields =
obj.getField(sfFinalFields).downcast<STObject>();
rpc::v1::LedgerObject* finalFieldsProto =
node->mutable_deleted_node()->mutable_final_fields();
populateFields(*finalFieldsProto, finalFields, lgrType);
}
}
}
}
void
populateAmount(rpc::v1::CurrencyAmount& proto, STAmount const& amount)
{
if (amount.native())
{
proto.mutable_xrp_amount()->set_drops(amount.xrp().drops());
}
else
{
rpc::v1::IssuedCurrencyAmount* issued =
proto.mutable_issued_currency_amount();
Issue const& issue = amount.issue();
Currency currency = issue.currency;
issued->mutable_currency()->set_name(to_string(issue.currency));
issued->mutable_currency()->set_code(currency.data(), currency.size());
issued->set_value(to_string(amount.iou()));
issued->mutable_issuer()->set_address(toBase58(issue.account));
}
}
void
populateTransaction(
rpc::v1::Transaction& proto,
std::shared_ptr<STTx const> txnSt)
{
AccountID account = txnSt->getAccountID(sfAccount);
proto.mutable_account()->set_address(toBase58(account));
STAmount amount = txnSt->getFieldAmount(sfAmount);
populateAmount(*proto.mutable_payment()->mutable_amount(), amount);
AccountID accountDest = txnSt->getAccountID(sfDestination);
proto.mutable_payment()->mutable_destination()->set_address(
toBase58(accountDest));
STAmount fee = txnSt->getFieldAmount(sfFee);
proto.mutable_fee()->set_drops(fee.xrp().drops());
proto.set_sequence(txnSt->getFieldU32(sfSequence));
Blob signingPubKey = txnSt->getFieldVL(sfSigningPubKey);
proto.set_signing_public_key(signingPubKey.data(), signingPubKey.size());
proto.set_flags(txnSt->getFieldU32(sfFlags));
proto.set_last_ledger_sequence(txnSt->getFieldU32(sfLastLedgerSequence));
Blob blob = txnSt->getFieldVL(sfTxnSignature);
proto.set_signature(blob.data(), blob.size());
if (txnSt->isFieldPresent(sfSourceTag))
{
proto.set_source_tag(txnSt->getFieldU32(sfSourceTag));
}
if (txnSt->isFieldPresent(sfAccountTxnID))
{
auto field = txnSt->getFieldH256(sfAccountTxnID);
proto.set_account_transaction_id(field.data(), field.size());
}
if (txnSt->isFieldPresent(sfMemos))
{
auto memos = txnSt->getFieldArray(sfMemos);
for (auto it = memos.begin(); it != memos.end(); ++it)
{
rpc::v1::Memo* elt = proto.add_memos();
auto memo = it->getField(sfMemo).downcast<STObject>();
if (memo.isFieldPresent(sfMemoData))
{
auto memoData = memo.getFieldVL(sfMemoData);
elt->set_memo_data(memoData.data(), memoData.size());
}
if (memo.isFieldPresent(sfMemoFormat))
{
auto memoFormat = memo.getFieldVL(sfMemoFormat);
elt->set_memo_format(memoFormat.data(), memoFormat.size());
}
if (memo.isFieldPresent(sfMemoType))
{
auto memoType = memo.getFieldVL(sfMemoType);
elt->set_memo_type(memoType.data(), memoType.size());
}
}
}
if (txnSt->isFieldPresent(sfSigners))
{
auto signers = txnSt->getFieldArray(sfSigners);
for (auto it = signers.begin(); it != signers.end(); ++it)
{
rpc::v1::Signer* elt = proto.add_signers();
auto signer = it->getField(sfSigner).downcast<STObject>();
if (signer.isFieldPresent(sfAccount))
{
elt->mutable_account()->set_address(
toBase58(signer.getAccountID(sfAccount)));
}
if (signer.isFieldPresent(sfTxnSignature))
{
auto sig = signer.getFieldVL(sfTxnSignature);
elt->set_transaction_signature(sig.data(), sig.size());
}
if (signer.isFieldPresent(sfSigningPubKey))
{
auto pubKey = signer.getFieldVL(sfSigningPubKey);
elt->set_signing_public_key(pubKey.data(), pubKey.size());
}
}
}
if (safe_cast<TxType>(txnSt->getFieldU16(sfTransactionType)) ==
TxType::ttPAYMENT)
{
if (txnSt->isFieldPresent(sfSendMax))
{
STAmount const& sendMax = txnSt->getFieldAmount(sfSendMax);
populateAmount(
*proto.mutable_payment()->mutable_send_max(), sendMax);
}
if (txnSt->isFieldPresent(sfInvoiceID))
{
auto invoice = txnSt->getFieldH256(sfInvoiceID);
proto.mutable_payment()->set_invoice_id(
invoice.data(), invoice.size());
}
if (txnSt->isFieldPresent(sfDestinationTag))
{
proto.mutable_payment()->set_destination_tag(
txnSt->getFieldU32(sfDestinationTag));
}
// populate path data
STPathSet const& pathset = txnSt->getFieldPathSet(sfPaths);
for (auto it = pathset.begin(); it < pathset.end(); ++it)
{
STPath const& path = *it;
rpc::v1::Path* protoPath = proto.mutable_payment()->add_paths();
for (auto it2 = path.begin(); it2 != path.end(); ++it2)
{
rpc::v1::PathElement* protoElement = protoPath->add_elements();
STPathElement const& elt = *it2;
if (elt.isOffer())
{
if (elt.hasCurrency())
{
Currency const& currency = elt.getCurrency();
protoElement->mutable_currency()->set_name(
to_string(currency));
}
if (elt.hasIssuer())
{
AccountID const& issuer = elt.getIssuerID();
protoElement->mutable_issuer()->set_address(
toBase58(issuer));
}
}
else
{
AccountID const& pathAccount = elt.getAccountID();
protoElement->mutable_account()->set_address(
toBase58(pathAccount));
}
}
}
}
}
void
populateTransactionResultType(rpc::v1::TransactionResult& proto, TER result)
{
if (isTecClaim(result))
{
proto.set_result_type(rpc::v1::TransactionResult::RESULT_TYPE_TEC);
}
if (isTefFailure(result))
{
proto.set_result_type(rpc::v1::TransactionResult::RESULT_TYPE_TEF);
}
if (isTelLocal(result))
{
proto.set_result_type(rpc::v1::TransactionResult::RESULT_TYPE_TEL);
}
if (isTemMalformed(result))
{
proto.set_result_type(rpc::v1::TransactionResult::RESULT_TYPE_TEM);
}
if (isTerRetry(result))
{
proto.set_result_type(rpc::v1::TransactionResult::RESULT_TYPE_TER);
}
if (isTesSuccess(result))
{
proto.set_result_type(rpc::v1::TransactionResult::RESULT_TYPE_TES);
}
}
beast::SemanticVersion const firstVersion("1.0.0");
beast::SemanticVersion const goodVersion("1.0.0");
beast::SemanticVersion const lastVersion("1.0.0");

View File

@@ -29,9 +29,9 @@
#include <ripple/rpc/Status.h>
#include <ripple/app/misc/NetworkOPs.h>
#include <ripple/app/misc/TxQ.h>
#include <rpc/v1/xrp_ledger.pb.h>
#include <org/xrpl/rpc/v1/xrp_ledger.pb.h>
#include <boost/optional.hpp>
#include <rpc/v1/xrp_ledger.pb.h>
#include <org/xrpl/rpc/v1/xrp_ledger.pb.h>
namespace Json {
class Value;
@@ -82,6 +82,37 @@ getAccountObjects (ReadView const& ledger, AccountID const& account,
boost::optional<std::vector<LedgerEntryType>> const& typeFilter, uint256 dirIndex,
uint256 const& entryIndex, std::uint32_t const limit, Json::Value& jvResult);
/** Get ledger by hash
If there is no error in the return value, the ledger pointer will have
been filled
*/
Status
getLedger(std::shared_ptr<ReadView const>& ledger, uint256 const & ledgerHash, Context& context);
/** Get ledger by sequence
If there is no error in the return value, the ledger pointer will have
been filled
*/
template <class T>
Status
getLedger(T& ledger, uint32_t ledgerIndex, Context& context);
enum LedgerShortcut
{
CURRENT,
CLOSED,
VALIDATED
};
/** Get ledger specified in shortcut.
If there is no error in the return value, the ledger pointer will have
been filled
*/
template <class T>
Status
getLedger(T& ledger, LedgerShortcut shortcut, Context& context);
/** Look up a ledger from a request and fill a Json::Result with either
an error, or data representing a ledger.
@@ -103,7 +134,7 @@ template <class T>
Status
ledgerFromRequest(
T& ledger,
GRPCContext<rpc::v1::GetAccountInfoRequest>& context);
GRPCContext<org::xrpl::rpc::v1::GetAccountInfoRequest>& context);
bool
isValidated(LedgerMaster& ledgerMaster, ReadView const& ledger,
@@ -204,45 +235,6 @@ std::pair<RPC::Status, LedgerEntryType>
*/
unsigned int getAPIVersionNumber(const Json::Value & value);
/*
* For all of the below populate* functions, the proto argument is an
* output parameter, and is populated with the data stored in the
* serialized object
*/
void
populateAccountRoot(rpc::v1::AccountRoot& proto, STObject const& obj);
void
populateRippleState(rpc::v1::RippleState& proto, STObject const& obj);
void
populateOffer(rpc::v1::Offer& proto, STObject const& obj);
void
populateSignerList(rpc::v1::SignerList& proto, STObject const& obj);
void
populateQueueData(
rpc::v1::QueueData& proto,
std::map<TxSeq, TxQ::AccountTxDetails const> const& txs);
void
populateDirectoryNode(rpc::v1::DirectoryNode& proto, STObject const& obj);
void
populateMeta(rpc::v1::Meta& proto, std::shared_ptr<TxMeta> txMeta);
void
populateTransaction(
rpc::v1::Transaction& proto,
std::shared_ptr<STTx const> txnSt);
void
populateAmount(rpc::v1::CurrencyAmount& proto, STAmount const& amount);
void
populateTransactionResultType(rpc::v1::TransactionResult& proto, TER result);
} // RPC
} // ripple