mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-28 06:25:49 +00:00
Compare commits
5 Commits
sync-2.1.0
...
sync-2.1.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89890e40d9 | ||
|
|
0a1a289bd4 | ||
|
|
827e6fe617 | ||
|
|
99ee7814e1 | ||
|
|
60e80c0427 |
@@ -168,6 +168,7 @@ printHelp(const po::options_description& desc)
|
||||
" peer_reservations_list\n"
|
||||
" ripple ...\n"
|
||||
" ripple_path_find <json> [<ledger>]\n"
|
||||
" server_definitions [<hash>]\n"
|
||||
" server_info [counters]\n"
|
||||
" server_state [counters]\n"
|
||||
" sign <private_key> <tx_json> [offline]\n"
|
||||
|
||||
@@ -134,7 +134,7 @@ withinRelativeDistance(
|
||||
template <typename Amt>
|
||||
requires(
|
||||
std::is_same_v<Amt, STAmount> || std::is_same_v<Amt, IOUAmount> ||
|
||||
std::is_same_v<Amt, XRPAmount>)
|
||||
std::is_same_v<Amt, XRPAmount> || std::is_same_v<Amt, Number>)
|
||||
bool
|
||||
withinRelativeDistance(Amt const& calc, Amt const& req, Number const& dist)
|
||||
{
|
||||
|
||||
@@ -137,10 +137,17 @@ private:
|
||||
TAmounts<TIn, TOut>
|
||||
generateFibSeqOffer(TAmounts<TIn, TOut> const& balances) const;
|
||||
|
||||
/** Generate max offer
|
||||
/** Generate max offer.
|
||||
* If `fixAMMOverflowOffer` is active, the offer is generated as:
|
||||
* takerGets = 99% * balances.out takerPays = swapOut(takerGets).
|
||||
* Return nullopt if takerGets is 0 or takerGets == balances.out.
|
||||
*
|
||||
* If `fixAMMOverflowOffer` is not active, the offer is generated as:
|
||||
* takerPays = max input amount;
|
||||
* takerGets = swapIn(takerPays).
|
||||
*/
|
||||
AMMOffer<TIn, TOut>
|
||||
maxOffer(TAmounts<TIn, TOut> const& balances) const;
|
||||
std::optional<AMMOffer<TIn, TOut>>
|
||||
maxOffer(TAmounts<TIn, TOut> const& balances, Rules const& rules) const;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -50,9 +50,8 @@ private:
|
||||
// the swap out of the entire side of the pool, in which case
|
||||
// the swap in amount is infinite.
|
||||
TAmounts<TIn, TOut> const amounts_;
|
||||
// If seated then current pool balances. Used in one-path limiting steps
|
||||
// to swap in/out.
|
||||
std::optional<TAmounts<TIn, TOut>> const balances_;
|
||||
// Current pool balances.
|
||||
TAmounts<TIn, TOut> const balances_;
|
||||
// The Spot Price quality if balances != amounts
|
||||
// else the amounts quality
|
||||
Quality const quality_;
|
||||
@@ -63,7 +62,7 @@ public:
|
||||
AMMOffer(
|
||||
AMMLiquidity<TIn, TOut> const& ammLiquidity,
|
||||
TAmounts<TIn, TOut> const& amounts,
|
||||
std::optional<TAmounts<TIn, TOut>> const& balances,
|
||||
TAmounts<TIn, TOut> const& balances,
|
||||
Quality const& quality);
|
||||
|
||||
Quality
|
||||
@@ -142,6 +141,12 @@ public:
|
||||
// AMM doesn't pay transfer fee on Payment tx
|
||||
return {ofrInRate, QUALITY_ONE};
|
||||
}
|
||||
|
||||
/** Check the new pool product is greater or equal to the old pool
|
||||
* product or if decreases then within some threshold.
|
||||
*/
|
||||
bool
|
||||
checkInvariant(TAmounts<TIn, TOut> const& consumed, beast::Journal j) const;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -93,6 +93,7 @@ AMMLiquidity<TIn, TOut>::generateFibSeqOffer(
|
||||
return cur;
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
constexpr T
|
||||
maxAmount()
|
||||
@@ -105,16 +106,41 @@ maxAmount()
|
||||
return STAmount(STAmount::cMaxValue / 2, STAmount::cMaxOffset);
|
||||
}
|
||||
|
||||
template <typename TIn, typename TOut>
|
||||
AMMOffer<TIn, TOut>
|
||||
AMMLiquidity<TIn, TOut>::maxOffer(TAmounts<TIn, TOut> const& balances) const
|
||||
template <typename T>
|
||||
T
|
||||
maxOut(T const& out, Issue const& iss)
|
||||
{
|
||||
return AMMOffer<TIn, TOut>(
|
||||
*this,
|
||||
{maxAmount<TIn>(),
|
||||
swapAssetIn(balances, maxAmount<TIn>(), tradingFee_)},
|
||||
balances,
|
||||
Quality{balances});
|
||||
Number const res = out * Number{99, -2};
|
||||
return toAmount<T>(iss, res, Number::rounding_mode::downward);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
template <typename TIn, typename TOut>
|
||||
std::optional<AMMOffer<TIn, TOut>>
|
||||
AMMLiquidity<TIn, TOut>::maxOffer(
|
||||
TAmounts<TIn, TOut> const& balances,
|
||||
Rules const& rules) const
|
||||
{
|
||||
if (!rules.enabled(fixAMMOverflowOffer))
|
||||
{
|
||||
return AMMOffer<TIn, TOut>(
|
||||
*this,
|
||||
{maxAmount<TIn>(),
|
||||
swapAssetIn(balances, maxAmount<TIn>(), tradingFee_)},
|
||||
balances,
|
||||
Quality{balances});
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const out = maxOut<TOut>(balances.out, issueOut());
|
||||
if (out <= TOut{0} || out >= balances.out)
|
||||
return std::nullopt;
|
||||
return AMMOffer<TIn, TOut>(
|
||||
*this,
|
||||
{swapAssetOut(balances, out, tradingFee_), out},
|
||||
balances,
|
||||
Quality{balances});
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TIn, typename TOut>
|
||||
@@ -167,15 +193,16 @@ AMMLiquidity<TIn, TOut>::getOffer(
|
||||
if (clobQuality && Quality{amounts} < clobQuality)
|
||||
return std::nullopt;
|
||||
return AMMOffer<TIn, TOut>(
|
||||
*this, amounts, std::nullopt, Quality{amounts});
|
||||
*this, amounts, balances, Quality{amounts});
|
||||
}
|
||||
else if (!clobQuality)
|
||||
{
|
||||
// If there is no CLOB to compare against, return the largest
|
||||
// amount, which doesn't overflow. The size is going to be
|
||||
// changed in BookStep per either deliver amount limit, or
|
||||
// sendmax, or available output or input funds.
|
||||
return maxOffer(balances);
|
||||
// sendmax, or available output or input funds. Might return
|
||||
// nullopt if the pool is small.
|
||||
return maxOffer(balances, view.rules());
|
||||
}
|
||||
else if (
|
||||
auto const amounts =
|
||||
@@ -188,7 +215,10 @@ AMMLiquidity<TIn, TOut>::getOffer(
|
||||
catch (std::overflow_error const& e)
|
||||
{
|
||||
JLOG(j_.error()) << "AMMLiquidity::getOffer overflow " << e.what();
|
||||
return maxOffer(balances);
|
||||
if (!view.rules().enabled(fixAMMOverflowOffer))
|
||||
return maxOffer(balances, view.rules());
|
||||
else
|
||||
return std::nullopt;
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
|
||||
@@ -27,7 +27,7 @@ template <typename TIn, typename TOut>
|
||||
AMMOffer<TIn, TOut>::AMMOffer(
|
||||
AMMLiquidity<TIn, TOut> const& ammLiquidity,
|
||||
TAmounts<TIn, TOut> const& amounts,
|
||||
std::optional<TAmounts<TIn, TOut>> const& balances,
|
||||
TAmounts<TIn, TOut> const& balances,
|
||||
Quality const& quality)
|
||||
: ammLiquidity_(ammLiquidity)
|
||||
, amounts_(amounts)
|
||||
@@ -110,7 +110,7 @@ AMMOffer<TIn, TOut>::limitOut(
|
||||
// Change the offer size according to the conservation function. The offer
|
||||
// quality is increased in this case, but it doesn't matter since there is
|
||||
// only one path.
|
||||
return {swapAssetOut(*balances_, limit, ammLiquidity_.tradingFee()), limit};
|
||||
return {swapAssetOut(balances_, limit, ammLiquidity_.tradingFee()), limit};
|
||||
}
|
||||
|
||||
template <typename TIn, typename TOut>
|
||||
@@ -122,7 +122,7 @@ AMMOffer<TIn, TOut>::limitIn(
|
||||
// See the comments above in limitOut().
|
||||
if (ammLiquidity_.multiPath())
|
||||
return quality().ceil_in(offrAmt, limit);
|
||||
return {limit, swapAssetIn(*balances_, limit, ammLiquidity_.tradingFee())};
|
||||
return {limit, swapAssetIn(balances_, limit, ammLiquidity_.tradingFee())};
|
||||
}
|
||||
|
||||
template <typename TIn, typename TOut>
|
||||
@@ -132,7 +132,45 @@ AMMOffer<TIn, TOut>::getQualityFunc() const
|
||||
if (ammLiquidity_.multiPath())
|
||||
return QualityFunction{quality(), QualityFunction::CLOBLikeTag{}};
|
||||
return QualityFunction{
|
||||
*balances_, ammLiquidity_.tradingFee(), QualityFunction::AMMTag{}};
|
||||
balances_, ammLiquidity_.tradingFee(), QualityFunction::AMMTag{}};
|
||||
}
|
||||
|
||||
template <typename TIn, typename TOut>
|
||||
bool
|
||||
AMMOffer<TIn, TOut>::checkInvariant(
|
||||
TAmounts<TIn, TOut> const& consumed,
|
||||
beast::Journal j) const
|
||||
{
|
||||
if (consumed.in > amounts_.in || consumed.out > amounts_.out)
|
||||
{
|
||||
JLOG(j.error()) << "AMMOffer::checkInvariant failed: consumed "
|
||||
<< to_string(consumed.in) << " "
|
||||
<< to_string(consumed.out) << " amounts "
|
||||
<< to_string(amounts_.in) << " "
|
||||
<< to_string(amounts_.out);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Number const product = balances_.in * balances_.out;
|
||||
auto const newBalances = TAmounts<TIn, TOut>{
|
||||
balances_.in + consumed.in, balances_.out - consumed.out};
|
||||
Number const newProduct = newBalances.in * newBalances.out;
|
||||
|
||||
if (newProduct >= product ||
|
||||
withinRelativeDistance(product, newProduct, Number{1, -7}))
|
||||
return true;
|
||||
|
||||
JLOG(j.error()) << "AMMOffer::checkInvariant failed: balances "
|
||||
<< to_string(balances_.in) << " "
|
||||
<< to_string(balances_.out) << " new balances "
|
||||
<< to_string(newBalances.in) << " "
|
||||
<< to_string(newBalances.out) << " product/newProduct "
|
||||
<< product << " " << newProduct << " diff "
|
||||
<< (product != Number{0}
|
||||
? to_string((product - newProduct) / product)
|
||||
: "undefined");
|
||||
return false;
|
||||
}
|
||||
|
||||
template class AMMOffer<STAmount, STAmount>;
|
||||
|
||||
@@ -793,6 +793,17 @@ BookStep<TIn, TOut, TDerived>::consumeOffer(
|
||||
TAmounts<TIn, TOut> const& stepAmt,
|
||||
TOut const& ownerGives) const
|
||||
{
|
||||
if (!offer.checkInvariant(ofrAmt, j_))
|
||||
{
|
||||
// purposely written as separate if statements so we get logging even
|
||||
// when the amendment isn't active.
|
||||
if (sb.rules().enabled(fixAMMOverflowOffer))
|
||||
{
|
||||
Throw<FlowException>(
|
||||
tecINVARIANT_FAILED, "AMM pool product invariant failed.");
|
||||
}
|
||||
}
|
||||
|
||||
// The offer owner gets the ofrAmt. The difference between ofrAmt and
|
||||
// stepAmt is a transfer fee that goes to book_.in.account
|
||||
{
|
||||
|
||||
@@ -163,6 +163,15 @@ public:
|
||||
// CLOB offer pays the transfer fee
|
||||
return {ofrInRate, ofrOutRate};
|
||||
}
|
||||
|
||||
/** Check any required invariant. Limit order book offer
|
||||
* always returns true.
|
||||
*/
|
||||
bool
|
||||
checkInvariant(TAmounts<TIn, TOut> const&, beast::Journal j) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
using Offer = TOffer<>;
|
||||
|
||||
@@ -1340,6 +1340,20 @@ private:
|
||||
return jvRequest;
|
||||
}
|
||||
|
||||
// server_definitions [hash]
|
||||
Json::Value
|
||||
parseServerDefinitions(Json::Value const& jvParams)
|
||||
{
|
||||
Json::Value jvRequest{Json::objectValue};
|
||||
|
||||
if (jvParams.size() == 1)
|
||||
{
|
||||
jvRequest[jss::hash] = jvParams[0u].asString();
|
||||
}
|
||||
|
||||
return jvRequest;
|
||||
}
|
||||
|
||||
// server_info [counters]
|
||||
Json::Value
|
||||
parseServerInfo(Json::Value const& jvParams)
|
||||
@@ -1406,6 +1420,7 @@ public:
|
||||
{"channel_verify", &RPCParser::parseChannelVerify, 4, 4},
|
||||
{"connect", &RPCParser::parseConnect, 1, 2},
|
||||
{"consensus_info", &RPCParser::parseAsIs, 0, 0},
|
||||
{"crawl_shards", &RPCParser::parseAsIs, 0, 2},
|
||||
{"deposit_authorized", &RPCParser::parseDepositAuthorized, 2, 3},
|
||||
{"download_shard", &RPCParser::parseDownloadShard, 2, -1},
|
||||
{"feature", &RPCParser::parseFeature, 0, 2},
|
||||
@@ -1444,14 +1459,14 @@ public:
|
||||
1},
|
||||
{"peer_reservations_list", &RPCParser::parseAsIs, 0, 0},
|
||||
{"ripple_path_find", &RPCParser::parseRipplePathFind, 1, 2},
|
||||
{"sign", &RPCParser::parseSignSubmit, 2, 3},
|
||||
{"sign_for", &RPCParser::parseSignFor, 3, 4},
|
||||
{"submit", &RPCParser::parseSignSubmit, 1, 3},
|
||||
{"submit_multisigned", &RPCParser::parseSubmitMultiSigned, 1, 1},
|
||||
{"server_definitions", &RPCParser::parseServerDefinitions, 0, 1},
|
||||
{"server_info", &RPCParser::parseServerInfo, 0, 1},
|
||||
{"server_state", &RPCParser::parseServerInfo, 0, 1},
|
||||
{"crawl_shards", &RPCParser::parseAsIs, 0, 2},
|
||||
{"sign", &RPCParser::parseSignSubmit, 2, 3},
|
||||
{"sign_for", &RPCParser::parseSignFor, 3, 4},
|
||||
{"stop", &RPCParser::parseAsIs, 0, 0},
|
||||
{"submit", &RPCParser::parseSignSubmit, 1, 3},
|
||||
{"submit_multisigned", &RPCParser::parseSubmitMultiSigned, 1, 1},
|
||||
{"transaction_entry", &RPCParser::parseTransactionEntry, 2, 2},
|
||||
{"tx", &RPCParser::parseTx, 1, 4},
|
||||
{"tx_history", &RPCParser::parseTxHistory, 1, 1},
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace detail {
|
||||
// Feature.cpp. Because it's only used to reserve storage, and determine how
|
||||
// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
|
||||
// the actual number of amendments. A LogicError on startup will verify this.
|
||||
static constexpr std::size_t numFeatures = 90;
|
||||
static constexpr std::size_t numFeatures = 91;
|
||||
|
||||
/** Amendments that this server supports and the default voting behavior.
|
||||
Whether they are enabled depends on the Rules defined in the validated
|
||||
@@ -378,6 +378,7 @@ extern uint256 const featureDID;
|
||||
extern uint256 const fixFillOrKill;
|
||||
extern uint256 const fixNFTokenReserve;
|
||||
extern uint256 const fixInnerObjTemplate;
|
||||
extern uint256 const fixAMMOverflowOffer;
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
|
||||
@@ -53,43 +53,65 @@ class STXChainBridge;
|
||||
class STVector256;
|
||||
class Definitions;
|
||||
|
||||
enum SerializedTypeID {
|
||||
// special types
|
||||
STI_UNKNOWN = -2,
|
||||
STI_NOTPRESENT = 0,
|
||||
#pragma push_macro("XMACRO")
|
||||
#undef XMACRO
|
||||
|
||||
// // types (common)
|
||||
STI_UINT16 = 1,
|
||||
STI_UINT32 = 2,
|
||||
STI_UINT64 = 3,
|
||||
STI_UINT128 = 4,
|
||||
STI_UINT256 = 5,
|
||||
STI_AMOUNT = 6,
|
||||
STI_VL = 7,
|
||||
STI_ACCOUNT = 8,
|
||||
// 9-13 are reserved
|
||||
STI_OBJECT = 14,
|
||||
STI_ARRAY = 15,
|
||||
#define XMACRO(STYPE) \
|
||||
/* special types */ \
|
||||
STYPE(STI_UNKNOWN, -2) \
|
||||
STYPE(STI_NOTPRESENT, 0) \
|
||||
STYPE(STI_UINT16, 1) \
|
||||
\
|
||||
/* types (common) */ \
|
||||
STYPE(STI_UINT32, 2) \
|
||||
STYPE(STI_UINT64, 3) \
|
||||
STYPE(STI_UINT128, 4) \
|
||||
STYPE(STI_UINT256, 5) \
|
||||
STYPE(STI_AMOUNT, 6) \
|
||||
STYPE(STI_VL, 7) \
|
||||
STYPE(STI_ACCOUNT, 8) \
|
||||
\
|
||||
/* 9-13 are reserved */ \
|
||||
STYPE(STI_OBJECT, 14) \
|
||||
STYPE(STI_ARRAY, 15) \
|
||||
\
|
||||
/* types (uncommon) */ \
|
||||
STYPE(STI_UINT8, 16) \
|
||||
STYPE(STI_UINT160, 17) \
|
||||
STYPE(STI_PATHSET, 18) \
|
||||
STYPE(STI_VECTOR256, 19) \
|
||||
STYPE(STI_UINT96, 20) \
|
||||
STYPE(STI_UINT192, 21) \
|
||||
STYPE(STI_UINT384, 22) \
|
||||
STYPE(STI_UINT512, 23) \
|
||||
STYPE(STI_ISSUE, 24) \
|
||||
STYPE(STI_XCHAIN_BRIDGE, 25) \
|
||||
\
|
||||
/* high-level types */ \
|
||||
/* cannot be serialized inside other types */ \
|
||||
STYPE(STI_TRANSACTION, 10001) \
|
||||
STYPE(STI_LEDGERENTRY, 10002) \
|
||||
STYPE(STI_VALIDATION, 10003) \
|
||||
STYPE(STI_METADATA, 10004)
|
||||
|
||||
// types (uncommon)
|
||||
STI_UINT8 = 16,
|
||||
STI_UINT160 = 17,
|
||||
STI_PATHSET = 18,
|
||||
STI_VECTOR256 = 19,
|
||||
STI_UINT96 = 20,
|
||||
STI_UINT192 = 21,
|
||||
STI_UINT384 = 22,
|
||||
STI_UINT512 = 23,
|
||||
STI_ISSUE = 24,
|
||||
STI_XCHAIN_BRIDGE = 25,
|
||||
#pragma push_macro("TO_ENUM")
|
||||
#undef TO_ENUM
|
||||
#pragma push_macro("TO_MAP")
|
||||
#undef TO_MAP
|
||||
|
||||
// high level types
|
||||
// cannot be serialized inside other types
|
||||
STI_TRANSACTION = 10001,
|
||||
STI_LEDGERENTRY = 10002,
|
||||
STI_VALIDATION = 10003,
|
||||
STI_METADATA = 10004,
|
||||
};
|
||||
#define TO_ENUM(name, value) name = value,
|
||||
#define TO_MAP(name, value) {#name, value},
|
||||
|
||||
enum SerializedTypeID { XMACRO(TO_ENUM) };
|
||||
|
||||
static std::map<std::string, int> const sTypeMap = {XMACRO(TO_MAP)};
|
||||
|
||||
#undef XMACRO
|
||||
#undef TO_ENUM
|
||||
|
||||
#pragma pop_macro("XMACRO")
|
||||
#pragma pop_macro("TO_ENUM")
|
||||
#pragma pop_macro("TO_MAP")
|
||||
|
||||
// constexpr
|
||||
inline int
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -668,6 +669,11 @@ isTecClaim(TER x)
|
||||
return ((x) >= tecCLAIM);
|
||||
}
|
||||
|
||||
std::unordered_map<
|
||||
TERUnderlyingType,
|
||||
std::pair<char const* const, char const* const>> const&
|
||||
transResults();
|
||||
|
||||
bool
|
||||
transResultInfo(TER code, std::string& token, std::string& text);
|
||||
|
||||
|
||||
@@ -483,7 +483,8 @@ REGISTER_FIX (fixDisallowIncomingV1, Supported::yes, VoteBehavior::De
|
||||
REGISTER_FEATURE(DID, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FIX(fixFillOrKill, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FIX (fixNFTokenReserve, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FIX(fixInnerObjTemplate, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FIX (fixInnerObjTemplate, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FIX (fixAMMOverflowOffer, Supported::yes, VoteBehavior::DefaultYes);
|
||||
|
||||
// The following amendments are obsolete, but must remain supported
|
||||
// because they could potentially get enabled.
|
||||
|
||||
@@ -20,13 +20,10 @@
|
||||
#include <ripple/protocol/TER.h>
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
namespace detail {
|
||||
|
||||
static std::unordered_map<
|
||||
std::unordered_map<
|
||||
TERUnderlyingType,
|
||||
std::pair<char const* const, char const* const>> const&
|
||||
transResults()
|
||||
@@ -239,12 +236,10 @@ transResults()
|
||||
return results;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
bool
|
||||
transResultInfo(TER code, std::string& token, std::string& text)
|
||||
{
|
||||
auto& results = detail::transResults();
|
||||
auto& results = transResults();
|
||||
|
||||
auto const r = results.find(TERtoInt(code));
|
||||
|
||||
@@ -278,7 +273,7 @@ std::optional<TER>
|
||||
transCode(std::string const& token)
|
||||
{
|
||||
static auto const results = [] {
|
||||
auto& byTer = detail::transResults();
|
||||
auto& byTer = transResults();
|
||||
auto range = boost::make_iterator_range(byTer.begin(), byTer.end());
|
||||
auto tRange = boost::adaptors::transform(range, [](auto const& r) {
|
||||
return std::make_pair(r.second.first, r.first);
|
||||
|
||||
@@ -110,8 +110,11 @@ JSS(HookParameterValue); // field
|
||||
JSS(HookParameter); // field
|
||||
JSS(HookGrant); // field
|
||||
JSS(isSerialized); // out: RPC server_definitions
|
||||
// matches definitions.json format
|
||||
JSS(isSigningField); // out: RPC server_definitions
|
||||
// matches definitions.json format
|
||||
JSS(isVLEncoded); // out: RPC server_definitions
|
||||
// matches definitions.json format
|
||||
JSS(Import);
|
||||
JSS(ImportVLSequence);
|
||||
JSS(Invalid); //
|
||||
@@ -788,8 +791,11 @@ JSS(type); // in: AccountObjects
|
||||
// out: NetworkOPs RPC server_definitions
|
||||
// OverlayImpl, Logic
|
||||
JSS(TRANSACTION_RESULTS); // out: RPC server_definitions
|
||||
// matches definitions.json format
|
||||
JSS(TRANSACTION_TYPES); // out: RPC server_definitions
|
||||
// matches definitions.json format
|
||||
JSS(TYPES); // out: RPC server_definitions
|
||||
// matches definitions.json format
|
||||
JSS(TRANSACTION_FLAGS); // out: RPC server_definitions
|
||||
JSS(TRANSACTION_FLAGS_INDICES); // out: RPC server_definitions
|
||||
JSS(type_hex); // out: STPathSet
|
||||
|
||||
@@ -20,10 +20,21 @@
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/misc/NetworkOPs.h>
|
||||
#include <ripple/app/reporting/P2pProxy.h>
|
||||
#include <ripple/json/json_value.h>
|
||||
#include <ripple/net/RPCErr.h>
|
||||
#include <ripple/protocol/LedgerFormats.h>
|
||||
#include <ripple/protocol/SField.h>
|
||||
#include <ripple/protocol/TER.h>
|
||||
#include <ripple/protocol/TxFormats.h>
|
||||
#include <ripple/protocol/digest.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <ripple/rpc/Context.h>
|
||||
#include <ripple/rpc/Role.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
Json::Value
|
||||
|
||||
@@ -100,6 +100,7 @@ Handler const handlerArray[]{
|
||||
{"channel_verify", byRef(&doChannelVerify), Role::USER, NO_CONDITION},
|
||||
{"connect", byRef(&doConnect), Role::ADMIN, NO_CONDITION},
|
||||
{"consensus_info", byRef(&doConsensusInfo), Role::ADMIN, NO_CONDITION},
|
||||
{"crawl_shards", byRef(&doCrawlShards), Role::ADMIN, NO_CONDITION},
|
||||
{"deposit_authorized",
|
||||
byRef(&doDepositAuthorized),
|
||||
Role::USER,
|
||||
@@ -114,6 +115,7 @@ Handler const handlerArray[]{
|
||||
{"feature", byRef(&doFeature), Role::ADMIN, NO_CONDITION},
|
||||
{"fee", byRef(&doFee), Role::USER, NEEDS_CURRENT_LEDGER},
|
||||
{"fetch_info", byRef(&doFetchInfo), Role::ADMIN, NO_CONDITION},
|
||||
{"inject", byRef(&doInject), Role::ADMIN, NEEDS_CURRENT_LEDGER},
|
||||
{"ledger_accept",
|
||||
byRef(&doLedgerAccept),
|
||||
Role::ADMIN,
|
||||
@@ -159,22 +161,20 @@ Handler const handlerArray[]{
|
||||
Role::ADMIN,
|
||||
NO_CONDITION},
|
||||
{"ripple_path_find", byRef(&doRipplePathFind), Role::USER, NO_CONDITION},
|
||||
{"sign", byRef(&doSign), Role::USER, NO_CONDITION},
|
||||
{"sign_for", byRef(&doSignFor), Role::USER, NO_CONDITION},
|
||||
{"inject", byRef(&doInject), Role::ADMIN, NEEDS_CURRENT_LEDGER},
|
||||
{"submit", byRef(&doSubmit), Role::USER, NEEDS_CURRENT_LEDGER},
|
||||
{"submit_multisigned",
|
||||
byRef(&doSubmitMultiSigned),
|
||||
Role::USER,
|
||||
NEEDS_CURRENT_LEDGER},
|
||||
{"server_definitions",
|
||||
byRef(&doServerDefinitions),
|
||||
Role::USER,
|
||||
NO_CONDITION},
|
||||
{"server_info", byRef(&doServerInfo), Role::USER, NO_CONDITION},
|
||||
{"server_state", byRef(&doServerState), Role::USER, NO_CONDITION},
|
||||
{"crawl_shards", byRef(&doCrawlShards), Role::ADMIN, NO_CONDITION},
|
||||
{"sign", byRef(&doSign), Role::USER, NO_CONDITION},
|
||||
{"sign_for", byRef(&doSignFor), Role::USER, NO_CONDITION},
|
||||
{"stop", byRef(&doStop), Role::ADMIN, NO_CONDITION},
|
||||
{"submit", byRef(&doSubmit), Role::USER, NEEDS_CURRENT_LEDGER},
|
||||
{"submit_multisigned",
|
||||
byRef(&doSubmitMultiSigned),
|
||||
Role::USER,
|
||||
NEEDS_CURRENT_LEDGER},
|
||||
{"transaction_entry", byRef(&doTransactionEntry), Role::USER, NO_CONDITION},
|
||||
{"tx", byRef(&doTxJson), Role::USER, NEEDS_NETWORK_CONNECTION},
|
||||
{"tx_history", byRef(&doTxHistory), Role::USER, NO_CONDITION, 1, 1},
|
||||
|
||||
@@ -80,6 +80,8 @@ admin = 127.0.0.1
|
||||
void
|
||||
testServerInfo()
|
||||
{
|
||||
testcase("server_info");
|
||||
|
||||
using namespace test::jtx;
|
||||
|
||||
{
|
||||
@@ -152,6 +154,8 @@ admin = 127.0.0.1
|
||||
void
|
||||
testServerDefinitions()
|
||||
{
|
||||
testcase("server_definitions");
|
||||
|
||||
using namespace test::jtx;
|
||||
|
||||
{
|
||||
@@ -159,6 +163,84 @@ admin = 127.0.0.1
|
||||
auto const result = env.rpc("server_definitions");
|
||||
BEAST_EXPECT(!result[jss::result].isMember(jss::error));
|
||||
BEAST_EXPECT(result[jss::result][jss::status] == "success");
|
||||
BEAST_EXPECT(result[jss::result].isMember(jss::FIELDS));
|
||||
BEAST_EXPECT(result[jss::result].isMember(jss::LEDGER_ENTRY_TYPES));
|
||||
BEAST_EXPECT(
|
||||
result[jss::result].isMember(jss::TRANSACTION_RESULTS));
|
||||
BEAST_EXPECT(result[jss::result].isMember(jss::TRANSACTION_TYPES));
|
||||
BEAST_EXPECT(result[jss::result].isMember(jss::TYPES));
|
||||
BEAST_EXPECT(result[jss::result].isMember(jss::hash));
|
||||
|
||||
// test a random element of each result
|
||||
// (testing the whole output would be difficult to maintain)
|
||||
|
||||
{
|
||||
auto const firstField = result[jss::result][jss::FIELDS][0u];
|
||||
BEAST_EXPECT(firstField[0u].asString() == "Generic");
|
||||
BEAST_EXPECT(
|
||||
firstField[1][jss::isSerialized].asBool() == false);
|
||||
BEAST_EXPECT(
|
||||
firstField[1][jss::isSigningField].asBool() == false);
|
||||
BEAST_EXPECT(firstField[1][jss::isVLEncoded].asBool() == false);
|
||||
BEAST_EXPECT(firstField[1][jss::nth].asUInt() == 0);
|
||||
BEAST_EXPECT(firstField[1][jss::type].asString() == "Unknown");
|
||||
}
|
||||
|
||||
BEAST_EXPECT(
|
||||
result[jss::result][jss::LEDGER_ENTRY_TYPES]["AccountRoot"]
|
||||
.asUInt() == 97);
|
||||
BEAST_EXPECT(
|
||||
result[jss::result][jss::TRANSACTION_RESULTS]["tecDIR_FULL"]
|
||||
.asUInt() == 121);
|
||||
BEAST_EXPECT(
|
||||
result[jss::result][jss::TRANSACTION_TYPES]["Payment"]
|
||||
.asUInt() == 0);
|
||||
BEAST_EXPECT(
|
||||
result[jss::result][jss::TYPES]["AccountID"].asUInt() == 8);
|
||||
}
|
||||
|
||||
// test providing the same hash
|
||||
{
|
||||
Env env(*this);
|
||||
auto const firstResult = env.rpc("server_definitions");
|
||||
auto const hash = firstResult[jss::result][jss::hash].asString();
|
||||
auto const hashParam =
|
||||
std::string("{ ") + "\"hash\": \"" + hash + "\"}";
|
||||
|
||||
auto const result =
|
||||
env.rpc("json", "server_definitions", hashParam);
|
||||
BEAST_EXPECT(!result[jss::result].isMember(jss::error));
|
||||
BEAST_EXPECT(result[jss::result][jss::status] == "success");
|
||||
BEAST_EXPECT(!result[jss::result].isMember(jss::FIELDS));
|
||||
BEAST_EXPECT(
|
||||
!result[jss::result].isMember(jss::LEDGER_ENTRY_TYPES));
|
||||
BEAST_EXPECT(
|
||||
!result[jss::result].isMember(jss::TRANSACTION_RESULTS));
|
||||
BEAST_EXPECT(!result[jss::result].isMember(jss::TRANSACTION_TYPES));
|
||||
BEAST_EXPECT(!result[jss::result].isMember(jss::TYPES));
|
||||
BEAST_EXPECT(result[jss::result].isMember(jss::hash));
|
||||
}
|
||||
|
||||
// test providing a different hash
|
||||
{
|
||||
Env env(*this);
|
||||
std::string const hash =
|
||||
"54296160385A27154BFA70A239DD8E8FD4CC2DB7BA32D970BA3A5B132CF749"
|
||||
"D1";
|
||||
auto const hashParam =
|
||||
std::string("{ ") + "\"hash\": \"" + hash + "\"}";
|
||||
|
||||
auto const result =
|
||||
env.rpc("json", "server_definitions", hashParam);
|
||||
BEAST_EXPECT(!result[jss::result].isMember(jss::error));
|
||||
BEAST_EXPECT(result[jss::result][jss::status] == "success");
|
||||
BEAST_EXPECT(result[jss::result].isMember(jss::FIELDS));
|
||||
BEAST_EXPECT(result[jss::result].isMember(jss::LEDGER_ENTRY_TYPES));
|
||||
BEAST_EXPECT(
|
||||
result[jss::result].isMember(jss::TRANSACTION_RESULTS));
|
||||
BEAST_EXPECT(result[jss::result].isMember(jss::TRANSACTION_TYPES));
|
||||
BEAST_EXPECT(result[jss::result].isMember(jss::TYPES));
|
||||
BEAST_EXPECT(result[jss::result].isMember(jss::hash));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user