From 268f86ca2a823715cd6034cbabdfd83803093df2 Mon Sep 17 00:00:00 2001 From: intelliot Date: Fri, 8 Sep 2023 05:51:22 +0000 Subject: [PATCH] deploy: c6f637501565cb34ebac8f51a32b65918473fef2 --- AMMInfo_8cpp_source.html | 2 +- GRPCHandlers_8h_source.html | 2 +- GRPCServer_8cpp_source.html | 2 +- Handler_8cpp_source.html | 2 +- Handlers_8h_source.html | 2 +- Issue_8cpp_source.html | 204 +++-- Issue_8h_source.html | 6 +- LedgerEntry_8cpp_source.html | 943 ++++++++++---------- LedgerRPC__test_8cpp_source.html | 1231 ++++++++++++++++----------- STAmount_8cpp_source.html | 2 +- STIssue_8cpp_source.html | 6 +- STIssue_8h_source.html | 2 +- STParsedJSON_8cpp_source.html | 2 +- classripple_1_1Issue.html | 2 +- classripple_1_1LedgerRPC__test.html | 10 +- namespaceripple.html | 14 +- 16 files changed, 1329 insertions(+), 1103 deletions(-) diff --git a/AMMInfo_8cpp_source.html b/AMMInfo_8cpp_source.html index fff9565f50..813a507601 100644 --- a/AMMInfo_8cpp_source.html +++ b/AMMInfo_8cpp_source.html @@ -367,7 +367,7 @@ $(function() {
bool isXRP(AccountID const &c)
Definition: AccountID.h:89
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
A generic endpoint for log messages.
Definition: Journal.h:58
-
Issue issueFromJson(Json::Value const &v)
Definition: Issue.cpp:77
+
Issue issueFromJson(Json::Value const &v)
Definition: Issue.cpp:78
const SF_UINT256 sfAMMID
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
std::optional< AccountID > getAccount(Json::Value const &v, Json::Value &result)
Definition: AMMInfo.cpp:32
diff --git a/GRPCHandlers_8h_source.html b/GRPCHandlers_8h_source.html index 6d094959a3..cb1d351103 100644 --- a/GRPCHandlers_8h_source.html +++ b/GRPCHandlers_8h_source.html @@ -127,7 +127,7 @@ $(function() {
std::pair< org::xrpl::rpc::v1::GetLedgerResponse, grpc::Status > doLedgerGrpc(RPC::GRPCContext< org::xrpl::rpc::v1::GetLedgerRequest > &context)
std::pair< org::xrpl::rpc::v1::GetLedgerDiffResponse, grpc::Status > doLedgerDiffGrpc(RPC::GRPCContext< org::xrpl::rpc::v1::GetLedgerDiffRequest > &context)
Definition: LedgerDiff.cpp:6
-
std::pair< org::xrpl::rpc::v1::GetLedgerEntryResponse, grpc::Status > doLedgerEntryGrpc(RPC::GRPCContext< org::xrpl::rpc::v1::GetLedgerEntryRequest > &context)
+
std::pair< org::xrpl::rpc::v1::GetLedgerEntryResponse, grpc::Status > doLedgerEntryGrpc(RPC::GRPCContext< org::xrpl::rpc::v1::GetLedgerEntryRequest > &context)
std::pair< org::xrpl::rpc::v1::GetLedgerDataResponse, grpc::Status > doLedgerDataGrpc(RPC::GRPCContext< org::xrpl::rpc::v1::GetLedgerDataRequest > &context)
Definition: LedgerData.cpp:135
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
diff --git a/GRPCServer_8cpp_source.html b/GRPCServer_8cpp_source.html index 60567066e7..9130caa7a5 100644 --- a/GRPCServer_8cpp_source.html +++ b/GRPCServer_8cpp_source.html @@ -839,7 +839,7 @@ $(function() {
std::shared_ptr< InfoSub > pointer
Definition: InfoSub.h:54
virtual LedgerMaster & getLedgerMaster()=0
@ USER
-
std::pair< org::xrpl::rpc::v1::GetLedgerEntryResponse, grpc::Status > doLedgerEntryGrpc(RPC::GRPCContext< org::xrpl::rpc::v1::GetLedgerEntryRequest > &context)
+
std::pair< org::xrpl::rpc::v1::GetLedgerEntryResponse, grpc::Status > doLedgerEntryGrpc(RPC::GRPCContext< org::xrpl::rpc::v1::GetLedgerEntryRequest > &context)
virtual Config & config()=0
Definition: Context.h:70
std::unique_ptr< org::xrpl::rpc::v1::XRPLedgerAPIService::Stub > getP2pForwardingStub(RPC::Context &context)
Get stub used to forward gRPC requests to a p2p node.
Definition: P2pProxy.cpp:35
diff --git a/Handler_8cpp_source.html b/Handler_8cpp_source.html index 6bd55ba352..9b270bd6da 100644 --- a/Handler_8cpp_source.html +++ b/Handler_8cpp_source.html @@ -330,7 +330,7 @@ $(function() {
Json::Value doLedgerAccept(RPC::JsonContext &)
Json::Value doUnlList(RPC::JsonContext &)
Definition: UnlList.cpp:30
Json::Value doGetCounts(RPC::JsonContext &context)
Definition: GetCounts.cpp:161
-
Json::Value doLedgerEntry(RPC::JsonContext &)
Definition: LedgerEntry.cpp:40
+
Json::Value doLedgerEntry(RPC::JsonContext &)
Definition: LedgerEntry.cpp:41
Json::Value doLedgerCurrent(RPC::JsonContext &)
Json::Value doAccountCurrencies(RPC::JsonContext &context)
STL class.
diff --git a/Handlers_8h_source.html b/Handlers_8h_source.html index 7e02f4ed9a..3cdcc989ad 100644 --- a/Handlers_8h_source.html +++ b/Handlers_8h_source.html @@ -247,7 +247,7 @@ $(function() {
Json::Value doLedgerAccept(RPC::JsonContext &)
Json::Value doUnlList(RPC::JsonContext &)
Definition: UnlList.cpp:30
Json::Value doGetCounts(RPC::JsonContext &context)
Definition: GetCounts.cpp:161
-
Json::Value doLedgerEntry(RPC::JsonContext &)
Definition: LedgerEntry.cpp:40
+
Json::Value doLedgerEntry(RPC::JsonContext &)
Definition: LedgerEntry.cpp:41
Json::Value doLedgerCurrent(RPC::JsonContext &)
Json::Value doAccountCurrencies(RPC::JsonContext &context)
Json::Value doValidationCreate(RPC::JsonContext &)
diff --git a/Issue_8cpp_source.html b/Issue_8cpp_source.html index d4440e445d..9286f01d85 100644 --- a/Issue_8cpp_source.html +++ b/Issue_8cpp_source.html @@ -90,118 +90,116 @@ $(function() {
19 
20 #include <ripple/protocol/Issue.h>
21 
-
22 #include <ripple/protocol/AccountID.h>
-
23 #include <ripple/protocol/UintTypes.h>
-
24 #include <ripple/protocol/jss.h>
-
25 
-
26 namespace ripple {
-
27 
-
28 std::string
-
29 Issue::getText() const
-
30 {
-
31  std::string ret;
-
32 
-
33  ret.reserve(64);
-
34  ret = to_string(currency);
-
35 
-
36  if (!isXRP(currency))
-
37  {
-
38  ret += "/";
-
39 
-
40  if (isXRP(account))
-
41  ret += "0";
-
42  else if (account == noAccount())
-
43  ret += "1";
-
44  else
-
45  ret += to_string(account);
-
46  }
-
47 
-
48  return ret;
-
49 }
-
50 
-
51 bool
-
52 isConsistent(Issue const& ac)
-
53 {
-
54  return isXRP(ac.currency) == isXRP(ac.account);
-
55 }
-
56 
-
57 std::string
-
58 to_string(Issue const& ac)
-
59 {
-
60  if (isXRP(ac.account))
-
61  return to_string(ac.currency);
-
62 
-
63  return to_string(ac.account) + "/" + to_string(ac.currency);
-
64 }
-
65 
-
66 Json::Value
-
67 to_json(Issue const& is)
-
68 {
-
69  Json::Value jv;
-
70  jv[jss::currency] = to_string(is.currency);
-
71  if (!isXRP(is.currency))
-
72  jv[jss::issuer] = toBase58(is.account);
-
73  return jv;
-
74 }
-
75 
-
76 Issue
-
77 issueFromJson(Json::Value const& v)
-
78 {
-
79  if (!v.isObject())
-
80  {
-
81  Throw<std::runtime_error>(
-
82  "issueFromJson can only be specified with a 'object' Json value");
-
83  }
-
84 
-
85  Json::Value const curStr = v[jss::currency];
-
86  Json::Value const issStr = v[jss::issuer];
-
87 
-
88  if (!curStr.isString())
-
89  {
-
90  Throw<std::runtime_error>(
-
91  "issueFromJson currency must be a string Json value");
-
92  }
-
93 
-
94  auto const currency = to_currency(curStr.asString());
-
95  if (currency == badCurrency() || currency == noCurrency())
-
96  {
-
97  Throw<std::runtime_error>(
-
98  "issueFromJson currency must be a valid currency");
+
22 #include <ripple/json/json_errors.h>
+
23 #include <ripple/protocol/AccountID.h>
+
24 #include <ripple/protocol/UintTypes.h>
+
25 #include <ripple/protocol/jss.h>
+
26 
+
27 namespace ripple {
+
28 
+
29 std::string
+
30 Issue::getText() const
+
31 {
+
32  std::string ret;
+
33 
+
34  ret.reserve(64);
+
35  ret = to_string(currency);
+
36 
+
37  if (!isXRP(currency))
+
38  {
+
39  ret += "/";
+
40 
+
41  if (isXRP(account))
+
42  ret += "0";
+
43  else if (account == noAccount())
+
44  ret += "1";
+
45  else
+
46  ret += to_string(account);
+
47  }
+
48 
+
49  return ret;
+
50 }
+
51 
+
52 bool
+
53 isConsistent(Issue const& ac)
+
54 {
+
55  return isXRP(ac.currency) == isXRP(ac.account);
+
56 }
+
57 
+
58 std::string
+
59 to_string(Issue const& ac)
+
60 {
+
61  if (isXRP(ac.account))
+
62  return to_string(ac.currency);
+
63 
+
64  return to_string(ac.account) + "/" + to_string(ac.currency);
+
65 }
+
66 
+
67 Json::Value
+
68 to_json(Issue const& is)
+
69 {
+
70  Json::Value jv;
+
71  jv[jss::currency] = to_string(is.currency);
+
72  if (!isXRP(is.currency))
+
73  jv[jss::issuer] = toBase58(is.account);
+
74  return jv;
+
75 }
+
76 
+
77 Issue
+
78 issueFromJson(Json::Value const& v)
+
79 {
+
80  if (!v.isObject())
+
81  {
+
82  Throw<Json::error>(
+
83  "issueFromJson can only be specified with a 'object' Json value");
+
84  }
+
85 
+
86  Json::Value const curStr = v[jss::currency];
+
87  Json::Value const issStr = v[jss::issuer];
+
88 
+
89  if (!curStr.isString())
+
90  {
+
91  Throw<Json::error>(
+
92  "issueFromJson currency must be a string Json value");
+
93  }
+
94 
+
95  auto const currency = to_currency(curStr.asString());
+
96  if (currency == badCurrency() || currency == noCurrency())
+
97  {
+
98  Throw<Json::error>("issueFromJson currency must be a valid currency");
99  }
100 
101  if (isXRP(currency))
102  {
103  if (!issStr.isNull())
104  {
-
105  Throw<std::runtime_error>("Issue, XRP should not have issuer");
+
105  Throw<Json::error>("Issue, XRP should not have issuer");
106  }
107  return xrpIssue();
108  }
109 
110  if (!issStr.isString())
111  {
-
112  Throw<std::runtime_error>(
-
113  "issueFromJson issuer must be a string Json value");
-
114  }
-
115  auto const issuer = parseBase58<AccountID>(issStr.asString());
-
116 
-
117  if (!issuer)
-
118  {
-
119  Throw<std::runtime_error>(
-
120  "issueFromJson issuer must be a valid account");
-
121  }
-
122 
-
123  return Issue{currency, *issuer};
-
124 }
-
125 
-
126 std::ostream&
-
127 operator<<(std::ostream& os, Issue const& x)
-
128 {
-
129  os << to_string(x);
-
130  return os;
-
131 }
-
132 
-
133 } // namespace ripple
+
112  Throw<Json::error>("issueFromJson issuer must be a string Json value");
+
113  }
+
114  auto const issuer = parseBase58<AccountID>(issStr.asString());
+
115 
+
116  if (!issuer)
+
117  {
+
118  Throw<Json::error>("issueFromJson issuer must be a valid account");
+
119  }
+
120 
+
121  return Issue{currency, *issuer};
+
122 }
+
123 
+
124 std::ostream&
+
125 operator<<(std::ostream& os, Issue const& x)
+
126 {
+
127  os << to_string(x);
+
128  return os;
+
129 }
+
130 
+
131 } // namespace ripple
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
Definition: UintTypes.cpp:135
bool to_currency(Currency &currency, std::string const &code)
Tries to convert a string to a Currency, returns true on success.
Definition: UintTypes.cpp:80
@@ -217,11 +215,11 @@ $(function() {
bool isNull() const
isNull() tests to see if this field is null.
Definition: json_value.cpp:967
std::ostream & operator<<(std::ostream &os, TOffer< TIn, TOut > const &offer)
Definition: Offer.h:303
STL class.
-
std::string getText() const
Definition: Issue.cpp:29
+
std::string getText() const
Definition: Issue.cpp:30
bool isXRP(AccountID const &c)
Definition: AccountID.h:89
-
Issue issueFromJson(Json::Value const &v)
Definition: Issue.cpp:77
+
Issue issueFromJson(Json::Value const &v)
Definition: Issue.cpp:78
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
-
Json::Value to_json(Issue const &is)
Definition: Issue.cpp:67
+
Json::Value to_json(Issue const &is)
Definition: Issue.cpp:68
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition: Issue.h:105
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
AccountID const & noAccount()
A placeholder for empty accounts.
Definition: AccountID.cpp:175
diff --git a/Issue_8h_source.html b/Issue_8h_source.html index 01b3882201..9535c61767 100644 --- a/Issue_8h_source.html +++ b/Issue_8h_source.html @@ -191,14 +191,14 @@ $(function() {
bool operator==(Manifest const &lhs, Manifest const &rhs)
Definition: Manifest.h:165
STL class.
-
std::string getText() const
Definition: Issue.cpp:29
+
std::string getText() const
Definition: Issue.cpp:30
AccountID const & xrpAccount()
Compute AccountID from public key.
Definition: AccountID.cpp:168
bool isXRP(AccountID const &c)
Definition: AccountID.h:89
-
Issue issueFromJson(Json::Value const &v)
Definition: Issue.cpp:77
+
Issue issueFromJson(Json::Value const &v)
Definition: Issue.cpp:78
Issue(Currency const &c, AccountID const &a)
Definition: Issue.h:45
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Issue()
Definition: Issue.h:41
-
Json::Value to_json(Issue const &is)
Definition: Issue.cpp:67
+
Json::Value to_json(Issue const &is)
Definition: Issue.cpp:68
std::enable_if_t< is_contiguously_hashable< T, Hasher >::value > hash_append(Hasher &h, T const &t) noexcept
Logically concatenate input data to a Hasher.
Definition: hash_append.h:236
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition: Issue.h:105
diff --git a/LedgerEntry_8cpp_source.html b/LedgerEntry_8cpp_source.html index 759d1dee8b..49d4da5a63 100644 --- a/LedgerEntry_8cpp_source.html +++ b/LedgerEntry_8cpp_source.html @@ -91,479 +91,508 @@ $(function() {
20 #include <ripple/app/main/Application.h>
21 #include <ripple/basics/StringUtilities.h>
22 #include <ripple/basics/strHex.h>
-
23 #include <ripple/ledger/ReadView.h>
-
24 #include <ripple/net/RPCErr.h>
-
25 #include <ripple/protocol/ErrorCodes.h>
-
26 #include <ripple/protocol/Indexes.h>
-
27 #include <ripple/protocol/jss.h>
-
28 #include <ripple/rpc/Context.h>
-
29 #include <ripple/rpc/GRPCHandlers.h>
-
30 #include <ripple/rpc/impl/RPCHelpers.h>
-
31 
-
32 namespace ripple {
-
33 
-
34 // {
-
35 // ledger_hash : <ledger>
-
36 // ledger_index : <ledger_index>
-
37 // ...
-
38 // }
-
39 Json::Value
-
40 doLedgerEntry(RPC::JsonContext& context)
-
41 {
-
42  std::shared_ptr<ReadView const> lpLedger;
-
43  auto jvResult = RPC::lookupLedger(lpLedger, context);
-
44 
-
45  if (!lpLedger)
-
46  return jvResult;
-
47 
-
48  uint256 uNodeIndex;
-
49  bool bNodeBinary = false;
-
50  LedgerEntryType expectedType = ltANY;
-
51 
-
52  if (context.params.isMember(jss::index))
-
53  {
-
54  if (!uNodeIndex.parseHex(context.params[jss::index].asString()))
-
55  {
-
56  uNodeIndex = beast::zero;
-
57  jvResult[jss::error] = "malformedRequest";
-
58  }
-
59  }
-
60  else if (context.params.isMember(jss::account_root))
-
61  {
-
62  expectedType = ltACCOUNT_ROOT;
-
63  auto const account = parseBase58<AccountID>(
-
64  context.params[jss::account_root].asString());
-
65  if (!account || account->isZero())
-
66  jvResult[jss::error] = "malformedAddress";
-
67  else
-
68  uNodeIndex = keylet::account(*account).key;
-
69  }
-
70  else if (context.params.isMember(jss::check))
-
71  {
-
72  expectedType = ltCHECK;
-
73 
-
74  if (!uNodeIndex.parseHex(context.params[jss::check].asString()))
-
75  {
-
76  uNodeIndex = beast::zero;
-
77  jvResult[jss::error] = "malformedRequest";
-
78  }
-
79  }
-
80  else if (context.params.isMember(jss::deposit_preauth))
-
81  {
-
82  expectedType = ltDEPOSIT_PREAUTH;
-
83 
-
84  if (!context.params[jss::deposit_preauth].isObject())
-
85  {
-
86  if (!context.params[jss::deposit_preauth].isString() ||
-
87  !uNodeIndex.parseHex(
-
88  context.params[jss::deposit_preauth].asString()))
-
89  {
-
90  uNodeIndex = beast::zero;
-
91  jvResult[jss::error] = "malformedRequest";
-
92  }
-
93  }
-
94  else if (
-
95  !context.params[jss::deposit_preauth].isMember(jss::owner) ||
-
96  !context.params[jss::deposit_preauth][jss::owner].isString() ||
-
97  !context.params[jss::deposit_preauth].isMember(jss::authorized) ||
-
98  !context.params[jss::deposit_preauth][jss::authorized].isString())
-
99  {
-
100  jvResult[jss::error] = "malformedRequest";
-
101  }
-
102  else
-
103  {
-
104  auto const owner = parseBase58<AccountID>(
-
105  context.params[jss::deposit_preauth][jss::owner].asString());
-
106 
-
107  auto const authorized = parseBase58<AccountID>(
-
108  context.params[jss::deposit_preauth][jss::authorized]
-
109  .asString());
-
110 
-
111  if (!owner)
-
112  jvResult[jss::error] = "malformedOwner";
-
113  else if (!authorized)
-
114  jvResult[jss::error] = "malformedAuthorized";
-
115  else
-
116  uNodeIndex = keylet::depositPreauth(*owner, *authorized).key;
-
117  }
-
118  }
-
119  else if (context.params.isMember(jss::directory))
-
120  {
-
121  expectedType = ltDIR_NODE;
-
122  if (context.params[jss::directory].isNull())
-
123  {
-
124  jvResult[jss::error] = "malformedRequest";
-
125  }
-
126  else if (!context.params[jss::directory].isObject())
-
127  {
-
128  if (!uNodeIndex.parseHex(context.params[jss::directory].asString()))
+
23 #include <ripple/json/json_errors.h>
+
24 #include <ripple/ledger/ReadView.h>
+
25 #include <ripple/net/RPCErr.h>
+
26 #include <ripple/protocol/ErrorCodes.h>
+
27 #include <ripple/protocol/Indexes.h>
+
28 #include <ripple/protocol/jss.h>
+
29 #include <ripple/rpc/Context.h>
+
30 #include <ripple/rpc/GRPCHandlers.h>
+
31 #include <ripple/rpc/impl/RPCHelpers.h>
+
32 
+
33 namespace ripple {
+
34 
+
35 // {
+
36 // ledger_hash : <ledger>
+
37 // ledger_index : <ledger_index>
+
38 // ...
+
39 // }
+
40 Json::Value
+
41 doLedgerEntry(RPC::JsonContext& context)
+
42 {
+
43  std::shared_ptr<ReadView const> lpLedger;
+
44  auto jvResult = RPC::lookupLedger(lpLedger, context);
+
45 
+
46  if (!lpLedger)
+
47  return jvResult;
+
48 
+
49  uint256 uNodeIndex;
+
50  bool bNodeBinary = false;
+
51  LedgerEntryType expectedType = ltANY;
+
52 
+
53  try
+
54  {
+
55  if (context.params.isMember(jss::index))
+
56  {
+
57  if (!uNodeIndex.parseHex(context.params[jss::index].asString()))
+
58  {
+
59  uNodeIndex = beast::zero;
+
60  jvResult[jss::error] = "malformedRequest";
+
61  }
+
62  }
+
63  else if (context.params.isMember(jss::account_root))
+
64  {
+
65  expectedType = ltACCOUNT_ROOT;
+
66  auto const account = parseBase58<AccountID>(
+
67  context.params[jss::account_root].asString());
+
68  if (!account || account->isZero())
+
69  jvResult[jss::error] = "malformedAddress";
+
70  else
+
71  uNodeIndex = keylet::account(*account).key;
+
72  }
+
73  else if (context.params.isMember(jss::check))
+
74  {
+
75  expectedType = ltCHECK;
+
76  if (!uNodeIndex.parseHex(context.params[jss::check].asString()))
+
77  {
+
78  uNodeIndex = beast::zero;
+
79  jvResult[jss::error] = "malformedRequest";
+
80  }
+
81  }
+
82  else if (context.params.isMember(jss::deposit_preauth))
+
83  {
+
84  expectedType = ltDEPOSIT_PREAUTH;
+
85 
+
86  if (!context.params[jss::deposit_preauth].isObject())
+
87  {
+
88  if (!context.params[jss::deposit_preauth].isString() ||
+
89  !uNodeIndex.parseHex(
+
90  context.params[jss::deposit_preauth].asString()))
+
91  {
+
92  uNodeIndex = beast::zero;
+
93  jvResult[jss::error] = "malformedRequest";
+
94  }
+
95  }
+
96  else if (
+
97  !context.params[jss::deposit_preauth].isMember(jss::owner) ||
+
98  !context.params[jss::deposit_preauth][jss::owner].isString() ||
+
99  !context.params[jss::deposit_preauth].isMember(
+
100  jss::authorized) ||
+
101  !context.params[jss::deposit_preauth][jss::authorized]
+
102  .isString())
+
103  {
+
104  jvResult[jss::error] = "malformedRequest";
+
105  }
+
106  else
+
107  {
+
108  auto const owner = parseBase58<AccountID>(
+
109  context.params[jss::deposit_preauth][jss::owner]
+
110  .asString());
+
111 
+
112  auto const authorized = parseBase58<AccountID>(
+
113  context.params[jss::deposit_preauth][jss::authorized]
+
114  .asString());
+
115 
+
116  if (!owner)
+
117  jvResult[jss::error] = "malformedOwner";
+
118  else if (!authorized)
+
119  jvResult[jss::error] = "malformedAuthorized";
+
120  else
+
121  uNodeIndex =
+
122  keylet::depositPreauth(*owner, *authorized).key;
+
123  }
+
124  }
+
125  else if (context.params.isMember(jss::directory))
+
126  {
+
127  expectedType = ltDIR_NODE;
+
128  if (context.params[jss::directory].isNull())
129  {
-
130  uNodeIndex = beast::zero;
-
131  jvResult[jss::error] = "malformedRequest";
-
132  }
-
133  }
-
134  else if (
-
135  context.params[jss::directory].isMember(jss::sub_index) &&
-
136  !context.params[jss::directory][jss::sub_index].isIntegral())
-
137  {
-
138  jvResult[jss::error] = "malformedRequest";
-
139  }
-
140  else
-
141  {
-
142  std::uint64_t uSubIndex =
-
143  context.params[jss::directory].isMember(jss::sub_index)
-
144  ? context.params[jss::directory][jss::sub_index].asUInt()
-
145  : 0;
-
146 
-
147  if (context.params[jss::directory].isMember(jss::dir_root))
+
130  jvResult[jss::error] = "malformedRequest";
+
131  }
+
132  else if (!context.params[jss::directory].isObject())
+
133  {
+
134  if (!uNodeIndex.parseHex(
+
135  context.params[jss::directory].asString()))
+
136  {
+
137  uNodeIndex = beast::zero;
+
138  jvResult[jss::error] = "malformedRequest";
+
139  }
+
140  }
+
141  else if (
+
142  context.params[jss::directory].isMember(jss::sub_index) &&
+
143  !context.params[jss::directory][jss::sub_index].isIntegral())
+
144  {
+
145  jvResult[jss::error] = "malformedRequest";
+
146  }
+
147  else
148  {
-
149  uint256 uDirRoot;
-
150 
-
151  if (context.params[jss::directory].isMember(jss::owner))
-
152  {
-
153  // May not specify both dir_root and owner.
-
154  jvResult[jss::error] = "malformedRequest";
-
155  }
-
156  else if (!uDirRoot.parseHex(
-
157  context.params[jss::directory][jss::dir_root]
-
158  .asString()))
-
159  {
-
160  uNodeIndex = beast::zero;
-
161  jvResult[jss::error] = "malformedRequest";
-
162  }
-
163  else
-
164  {
-
165  uNodeIndex = keylet::page(uDirRoot, uSubIndex).key;
-
166  }
-
167  }
-
168  else if (context.params[jss::directory].isMember(jss::owner))
-
169  {
-
170  auto const ownerID = parseBase58<AccountID>(
-
171  context.params[jss::directory][jss::owner].asString());
-
172 
-
173  if (!ownerID)
-
174  {
-
175  jvResult[jss::error] = "malformedAddress";
-
176  }
-
177  else
-
178  {
-
179  uNodeIndex =
-
180  keylet::page(keylet::ownerDir(*ownerID), uSubIndex).key;
-
181  }
-
182  }
-
183  else
-
184  {
-
185  jvResult[jss::error] = "malformedRequest";
-
186  }
-
187  }
-
188  }
-
189  else if (context.params.isMember(jss::escrow))
-
190  {
-
191  expectedType = ltESCROW;
-
192  if (!context.params[jss::escrow].isObject())
-
193  {
-
194  if (!uNodeIndex.parseHex(context.params[jss::escrow].asString()))
-
195  {
-
196  uNodeIndex = beast::zero;
-
197  jvResult[jss::error] = "malformedRequest";
-
198  }
-
199  }
-
200  else if (
-
201  !context.params[jss::escrow].isMember(jss::owner) ||
-
202  !context.params[jss::escrow].isMember(jss::seq) ||
-
203  !context.params[jss::escrow][jss::seq].isIntegral())
-
204  {
-
205  jvResult[jss::error] = "malformedRequest";
-
206  }
-
207  else
-
208  {
-
209  auto const id = parseBase58<AccountID>(
-
210  context.params[jss::escrow][jss::owner].asString());
-
211  if (!id)
-
212  jvResult[jss::error] = "malformedOwner";
-
213  else
-
214  uNodeIndex =
-
215  keylet::escrow(
-
216  *id, context.params[jss::escrow][jss::seq].asUInt())
-
217  .key;
-
218  }
-
219  }
-
220  else if (context.params.isMember(jss::offer))
-
221  {
-
222  expectedType = ltOFFER;
-
223  if (!context.params[jss::offer].isObject())
-
224  {
-
225  if (!uNodeIndex.parseHex(context.params[jss::offer].asString()))
-
226  {
-
227  uNodeIndex = beast::zero;
-
228  jvResult[jss::error] = "malformedRequest";
-
229  }
-
230  }
-
231  else if (
-
232  !context.params[jss::offer].isMember(jss::account) ||
-
233  !context.params[jss::offer].isMember(jss::seq) ||
-
234  !context.params[jss::offer][jss::seq].isIntegral())
-
235  {
-
236  jvResult[jss::error] = "malformedRequest";
-
237  }
-
238  else
-
239  {
-
240  auto const id = parseBase58<AccountID>(
-
241  context.params[jss::offer][jss::account].asString());
-
242  if (!id)
-
243  jvResult[jss::error] = "malformedAddress";
-
244  else
-
245  uNodeIndex =
-
246  keylet::offer(
-
247  *id, context.params[jss::offer][jss::seq].asUInt())
-
248  .key;
-
249  }
-
250  }
-
251  else if (context.params.isMember(jss::payment_channel))
-
252  {
-
253  expectedType = ltPAYCHAN;
-
254 
-
255  if (!uNodeIndex.parseHex(
-
256  context.params[jss::payment_channel].asString()))
-
257  {
-
258  uNodeIndex = beast::zero;
-
259  jvResult[jss::error] = "malformedRequest";
-
260  }
-
261  }
-
262  else if (context.params.isMember(jss::ripple_state))
-
263  {
-
264  expectedType = ltRIPPLE_STATE;
-
265  Currency uCurrency;
-
266  Json::Value jvRippleState = context.params[jss::ripple_state];
-
267 
-
268  if (!jvRippleState.isObject() ||
-
269  !jvRippleState.isMember(jss::currency) ||
-
270  !jvRippleState.isMember(jss::accounts) ||
-
271  !jvRippleState[jss::accounts].isArray() ||
-
272  2 != jvRippleState[jss::accounts].size() ||
-
273  !jvRippleState[jss::accounts][0u].isString() ||
-
274  !jvRippleState[jss::accounts][1u].isString() ||
-
275  (jvRippleState[jss::accounts][0u].asString() ==
-
276  jvRippleState[jss::accounts][1u].asString()))
-
277  {
-
278  jvResult[jss::error] = "malformedRequest";
-
279  }
-
280  else
-
281  {
-
282  auto const id1 = parseBase58<AccountID>(
-
283  jvRippleState[jss::accounts][0u].asString());
-
284  auto const id2 = parseBase58<AccountID>(
-
285  jvRippleState[jss::accounts][1u].asString());
-
286  if (!id1 || !id2)
-
287  {
-
288  jvResult[jss::error] = "malformedAddress";
-
289  }
-
290  else if (!to_currency(
-
291  uCurrency, jvRippleState[jss::currency].asString()))
-
292  {
-
293  jvResult[jss::error] = "malformedCurrency";
-
294  }
-
295  else
-
296  {
-
297  uNodeIndex = keylet::line(*id1, *id2, uCurrency).key;
-
298  }
-
299  }
-
300  }
-
301  else if (context.params.isMember(jss::ticket))
-
302  {
-
303  expectedType = ltTICKET;
-
304  if (!context.params[jss::ticket].isObject())
-
305  {
-
306  if (!uNodeIndex.parseHex(context.params[jss::ticket].asString()))
-
307  {
-
308  uNodeIndex = beast::zero;
-
309  jvResult[jss::error] = "malformedRequest";
-
310  }
-
311  }
-
312  else if (
-
313  !context.params[jss::ticket].isMember(jss::account) ||
-
314  !context.params[jss::ticket].isMember(jss::ticket_seq) ||
-
315  !context.params[jss::ticket][jss::ticket_seq].isIntegral())
-
316  {
-
317  jvResult[jss::error] = "malformedRequest";
-
318  }
-
319  else
-
320  {
-
321  auto const id = parseBase58<AccountID>(
-
322  context.params[jss::ticket][jss::account].asString());
-
323  if (!id)
-
324  jvResult[jss::error] = "malformedAddress";
-
325  else
-
326  uNodeIndex = getTicketIndex(
-
327  *id, context.params[jss::ticket][jss::ticket_seq].asUInt());
-
328  }
-
329  }
-
330  else if (context.params.isMember(jss::nft_page))
-
331  {
-
332  expectedType = ltNFTOKEN_PAGE;
-
333 
-
334  if (context.params[jss::nft_page].isString())
-
335  {
-
336  if (!uNodeIndex.parseHex(context.params[jss::nft_page].asString()))
-
337  {
-
338  uNodeIndex = beast::zero;
-
339  jvResult[jss::error] = "malformedRequest";
+
149  std::uint64_t uSubIndex =
+
150  context.params[jss::directory].isMember(jss::sub_index)
+
151  ? context.params[jss::directory][jss::sub_index].asUInt()
+
152  : 0;
+
153 
+
154  if (context.params[jss::directory].isMember(jss::dir_root))
+
155  {
+
156  uint256 uDirRoot;
+
157 
+
158  if (context.params[jss::directory].isMember(jss::owner))
+
159  {
+
160  // May not specify both dir_root and owner.
+
161  jvResult[jss::error] = "malformedRequest";
+
162  }
+
163  else if (!uDirRoot.parseHex(
+
164  context.params[jss::directory][jss::dir_root]
+
165  .asString()))
+
166  {
+
167  uNodeIndex = beast::zero;
+
168  jvResult[jss::error] = "malformedRequest";
+
169  }
+
170  else
+
171  {
+
172  uNodeIndex = keylet::page(uDirRoot, uSubIndex).key;
+
173  }
+
174  }
+
175  else if (context.params[jss::directory].isMember(jss::owner))
+
176  {
+
177  auto const ownerID = parseBase58<AccountID>(
+
178  context.params[jss::directory][jss::owner].asString());
+
179 
+
180  if (!ownerID)
+
181  {
+
182  jvResult[jss::error] = "malformedAddress";
+
183  }
+
184  else
+
185  {
+
186  uNodeIndex =
+
187  keylet::page(keylet::ownerDir(*ownerID), uSubIndex)
+
188  .key;
+
189  }
+
190  }
+
191  else
+
192  {
+
193  jvResult[jss::error] = "malformedRequest";
+
194  }
+
195  }
+
196  }
+
197  else if (context.params.isMember(jss::escrow))
+
198  {
+
199  expectedType = ltESCROW;
+
200  if (!context.params[jss::escrow].isObject())
+
201  {
+
202  if (!uNodeIndex.parseHex(
+
203  context.params[jss::escrow].asString()))
+
204  {
+
205  uNodeIndex = beast::zero;
+
206  jvResult[jss::error] = "malformedRequest";
+
207  }
+
208  }
+
209  else if (
+
210  !context.params[jss::escrow].isMember(jss::owner) ||
+
211  !context.params[jss::escrow].isMember(jss::seq) ||
+
212  !context.params[jss::escrow][jss::seq].isIntegral())
+
213  {
+
214  jvResult[jss::error] = "malformedRequest";
+
215  }
+
216  else
+
217  {
+
218  auto const id = parseBase58<AccountID>(
+
219  context.params[jss::escrow][jss::owner].asString());
+
220  if (!id)
+
221  jvResult[jss::error] = "malformedOwner";
+
222  else
+
223  uNodeIndex =
+
224  keylet::escrow(
+
225  *id, context.params[jss::escrow][jss::seq].asUInt())
+
226  .key;
+
227  }
+
228  }
+
229  else if (context.params.isMember(jss::offer))
+
230  {
+
231  expectedType = ltOFFER;
+
232  if (!context.params[jss::offer].isObject())
+
233  {
+
234  if (!uNodeIndex.parseHex(context.params[jss::offer].asString()))
+
235  {
+
236  uNodeIndex = beast::zero;
+
237  jvResult[jss::error] = "malformedRequest";
+
238  }
+
239  }
+
240  else if (
+
241  !context.params[jss::offer].isMember(jss::account) ||
+
242  !context.params[jss::offer].isMember(jss::seq) ||
+
243  !context.params[jss::offer][jss::seq].isIntegral())
+
244  {
+
245  jvResult[jss::error] = "malformedRequest";
+
246  }
+
247  else
+
248  {
+
249  auto const id = parseBase58<AccountID>(
+
250  context.params[jss::offer][jss::account].asString());
+
251  if (!id)
+
252  jvResult[jss::error] = "malformedAddress";
+
253  else
+
254  uNodeIndex =
+
255  keylet::offer(
+
256  *id, context.params[jss::offer][jss::seq].asUInt())
+
257  .key;
+
258  }
+
259  }
+
260  else if (context.params.isMember(jss::payment_channel))
+
261  {
+
262  expectedType = ltPAYCHAN;
+
263 
+
264  if (!uNodeIndex.parseHex(
+
265  context.params[jss::payment_channel].asString()))
+
266  {
+
267  uNodeIndex = beast::zero;
+
268  jvResult[jss::error] = "malformedRequest";
+
269  }
+
270  }
+
271  else if (context.params.isMember(jss::ripple_state))
+
272  {
+
273  expectedType = ltRIPPLE_STATE;
+
274  Currency uCurrency;
+
275  Json::Value jvRippleState = context.params[jss::ripple_state];
+
276 
+
277  if (!jvRippleState.isObject() ||
+
278  !jvRippleState.isMember(jss::currency) ||
+
279  !jvRippleState.isMember(jss::accounts) ||
+
280  !jvRippleState[jss::accounts].isArray() ||
+
281  2 != jvRippleState[jss::accounts].size() ||
+
282  !jvRippleState[jss::accounts][0u].isString() ||
+
283  !jvRippleState[jss::accounts][1u].isString() ||
+
284  (jvRippleState[jss::accounts][0u].asString() ==
+
285  jvRippleState[jss::accounts][1u].asString()))
+
286  {
+
287  jvResult[jss::error] = "malformedRequest";
+
288  }
+
289  else
+
290  {
+
291  auto const id1 = parseBase58<AccountID>(
+
292  jvRippleState[jss::accounts][0u].asString());
+
293  auto const id2 = parseBase58<AccountID>(
+
294  jvRippleState[jss::accounts][1u].asString());
+
295  if (!id1 || !id2)
+
296  {
+
297  jvResult[jss::error] = "malformedAddress";
+
298  }
+
299  else if (!to_currency(
+
300  uCurrency,
+
301  jvRippleState[jss::currency].asString()))
+
302  {
+
303  jvResult[jss::error] = "malformedCurrency";
+
304  }
+
305  else
+
306  {
+
307  uNodeIndex = keylet::line(*id1, *id2, uCurrency).key;
+
308  }
+
309  }
+
310  }
+
311  else if (context.params.isMember(jss::ticket))
+
312  {
+
313  expectedType = ltTICKET;
+
314  if (!context.params[jss::ticket].isObject())
+
315  {
+
316  if (!uNodeIndex.parseHex(
+
317  context.params[jss::ticket].asString()))
+
318  {
+
319  uNodeIndex = beast::zero;
+
320  jvResult[jss::error] = "malformedRequest";
+
321  }
+
322  }
+
323  else if (
+
324  !context.params[jss::ticket].isMember(jss::account) ||
+
325  !context.params[jss::ticket].isMember(jss::ticket_seq) ||
+
326  !context.params[jss::ticket][jss::ticket_seq].isIntegral())
+
327  {
+
328  jvResult[jss::error] = "malformedRequest";
+
329  }
+
330  else
+
331  {
+
332  auto const id = parseBase58<AccountID>(
+
333  context.params[jss::ticket][jss::account].asString());
+
334  if (!id)
+
335  jvResult[jss::error] = "malformedAddress";
+
336  else
+
337  uNodeIndex = getTicketIndex(
+
338  *id,
+
339  context.params[jss::ticket][jss::ticket_seq].asUInt());
340  }
341  }
-
342  else
+
342  else if (context.params.isMember(jss::nft_page))
343  {
-
344  jvResult[jss::error] = "malformedRequest";
-
345  }
-
346  }
-
347  else if (context.params.isMember(jss::amm))
-
348  {
-
349  expectedType = ltAMM;
-
350  if (!context.params[jss::amm].isObject())
-
351  {
-
352  if (!uNodeIndex.parseHex(context.params[jss::amm].asString()))
-
353  {
-
354  uNodeIndex = beast::zero;
-
355  jvResult[jss::error] = "malformedRequest";
-
356  }
-
357  }
-
358  else if (
-
359  !context.params[jss::amm].isMember(jss::asset) ||
-
360  !context.params[jss::amm].isMember(jss::asset2))
+
344  expectedType = ltNFTOKEN_PAGE;
+
345 
+
346  if (context.params[jss::nft_page].isString())
+
347  {
+
348  if (!uNodeIndex.parseHex(
+
349  context.params[jss::nft_page].asString()))
+
350  {
+
351  uNodeIndex = beast::zero;
+
352  jvResult[jss::error] = "malformedRequest";
+
353  }
+
354  }
+
355  else
+
356  {
+
357  jvResult[jss::error] = "malformedRequest";
+
358  }
+
359  }
+
360  else if (context.params.isMember(jss::amm))
361  {
-
362  jvResult[jss::error] = "malformedRequest";
-
363  }
-
364  else
-
365  {
-
366  try
-
367  {
-
368  auto const issue =
-
369  issueFromJson(context.params[jss::amm][jss::asset]);
-
370  auto const issue2 =
-
371  issueFromJson(context.params[jss::amm][jss::asset2]);
-
372  uNodeIndex = keylet::amm(issue, issue2).key;
-
373  }
-
374  catch (std::runtime_error const&)
-
375  {
-
376  jvResult[jss::error] = "malformedRequest";
-
377  }
-
378  }
-
379  }
-
380  else
-
381  {
-
382  if (context.params.isMember("params") &&
-
383  context.params["params"].isArray() &&
-
384  context.params["params"].size() == 1 &&
-
385  context.params["params"][0u].isString())
-
386  {
-
387  if (!uNodeIndex.parseHex(context.params["params"][0u].asString()))
-
388  {
-
389  uNodeIndex = beast::zero;
-
390  jvResult[jss::error] = "malformedRequest";
+
362  expectedType = ltAMM;
+
363  if (!context.params[jss::amm].isObject())
+
364  {
+
365  if (!uNodeIndex.parseHex(context.params[jss::amm].asString()))
+
366  {
+
367  uNodeIndex = beast::zero;
+
368  jvResult[jss::error] = "malformedRequest";
+
369  }
+
370  }
+
371  else if (
+
372  !context.params[jss::amm].isMember(jss::asset) ||
+
373  !context.params[jss::amm].isMember(jss::asset2))
+
374  {
+
375  jvResult[jss::error] = "malformedRequest";
+
376  }
+
377  else
+
378  {
+
379  try
+
380  {
+
381  auto const issue =
+
382  issueFromJson(context.params[jss::amm][jss::asset]);
+
383  auto const issue2 =
+
384  issueFromJson(context.params[jss::amm][jss::asset2]);
+
385  uNodeIndex = keylet::amm(issue, issue2).key;
+
386  }
+
387  catch (std::runtime_error const&)
+
388  {
+
389  jvResult[jss::error] = "malformedRequest";
+
390  }
391  }
392  }
393  else
394  {
-
395  if (context.apiVersion < 2u)
-
396  jvResult[jss::error] = "unknownOption";
-
397  else
-
398  jvResult[jss::error] = "invalidParams";
-
399  }
-
400  }
-
401 
-
402  if (uNodeIndex.isNonZero())
-
403  {
-
404  auto const sleNode = lpLedger->read(keylet::unchecked(uNodeIndex));
-
405  if (context.params.isMember(jss::binary))
-
406  bNodeBinary = context.params[jss::binary].asBool();
-
407 
-
408  if (!sleNode)
-
409  {
-
410  // Not found.
-
411  jvResult[jss::error] = "entryNotFound";
-
412  }
-
413  else if (
-
414  (expectedType != ltANY) && (expectedType != sleNode->getType()))
-
415  {
-
416  jvResult[jss::error] = "unexpectedLedgerType";
-
417  }
-
418  else if (bNodeBinary)
+
395  if (context.params.isMember("params") &&
+
396  context.params["params"].isArray() &&
+
397  context.params["params"].size() == 1 &&
+
398  context.params["params"][0u].isString())
+
399  {
+
400  if (!uNodeIndex.parseHex(
+
401  context.params["params"][0u].asString()))
+
402  {
+
403  uNodeIndex = beast::zero;
+
404  jvResult[jss::error] = "malformedRequest";
+
405  }
+
406  }
+
407  else
+
408  {
+
409  if (context.apiVersion < 2u)
+
410  jvResult[jss::error] = "unknownOption";
+
411  else
+
412  jvResult[jss::error] = "invalidParams";
+
413  }
+
414  }
+
415  }
+
416  catch (Json::error& e)
+
417  {
+
418  if (context.apiVersion > 1u)
419  {
-
420  Serializer s;
-
421 
-
422  sleNode->add(s);
-
423 
-
424  jvResult[jss::node_binary] = strHex(s.peekData());
-
425  jvResult[jss::index] = to_string(uNodeIndex);
-
426  }
-
427  else
-
428  {
-
429  jvResult[jss::node] = sleNode->getJson(JsonOptions::none);
-
430  jvResult[jss::index] = to_string(uNodeIndex);
-
431  }
-
432  }
-
433 
-
434  return jvResult;
-
435 }
-
436 
-
437 std::pair<org::xrpl::rpc::v1::GetLedgerEntryResponse, grpc::Status>
-
438 doLedgerEntryGrpc(
-
439  RPC::GRPCContext<org::xrpl::rpc::v1::GetLedgerEntryRequest>& context)
-
440 {
-
441  org::xrpl::rpc::v1::GetLedgerEntryRequest& request = context.params;
-
442  org::xrpl::rpc::v1::GetLedgerEntryResponse response;
-
443  grpc::Status status = grpc::Status::OK;
-
444 
-
445  std::shared_ptr<ReadView const> ledger;
-
446  if (auto status = RPC::ledgerFromRequest(ledger, context))
-
447  {
-
448  grpc::Status errorStatus;
-
449  if (status.toErrorCode() == rpcINVALID_PARAMS)
-
450  {
-
451  errorStatus = grpc::Status(
-
452  grpc::StatusCode::INVALID_ARGUMENT, status.message());
-
453  }
-
454  else
-
455  {
-
456  errorStatus =
-
457  grpc::Status(grpc::StatusCode::NOT_FOUND, status.message());
-
458  }
-
459  return {response, errorStatus};
+
420  // For apiVersion 2 onwards, any parsing failures that throw
+
421  // this
+
422  // exception return an invalidParam error.
+
423  uNodeIndex = beast::zero;
+
424  jvResult[jss::error] = "invalidParams";
+
425  }
+
426  else
+
427  throw;
+
428  }
+
429 
+
430  if (uNodeIndex.isNonZero())
+
431  {
+
432  auto const sleNode = lpLedger->read(keylet::unchecked(uNodeIndex));
+
433  if (context.params.isMember(jss::binary))
+
434  bNodeBinary = context.params[jss::binary].asBool();
+
435 
+
436  if (!sleNode)
+
437  {
+
438  // Not found.
+
439  jvResult[jss::error] = "entryNotFound";
+
440  }
+
441  else if (
+
442  (expectedType != ltANY) && (expectedType != sleNode->getType()))
+
443  {
+
444  jvResult[jss::error] = "unexpectedLedgerType";
+
445  }
+
446  else if (bNodeBinary)
+
447  {
+
448  Serializer s;
+
449 
+
450  sleNode->add(s);
+
451 
+
452  jvResult[jss::node_binary] = strHex(s.peekData());
+
453  jvResult[jss::index] = to_string(uNodeIndex);
+
454  }
+
455  else
+
456  {
+
457  jvResult[jss::node] = sleNode->getJson(JsonOptions::none);
+
458  jvResult[jss::index] = to_string(uNodeIndex);
+
459  }
460  }
461 
-
462  auto key = uint256::fromVoidChecked(request.key());
-
463  if (!key)
-
464  {
-
465  grpc::Status errorStatus{
-
466  grpc::StatusCode::INVALID_ARGUMENT, "index malformed"};
-
467  return {response, errorStatus};
-
468  }
-
469 
-
470  auto const sleNode = ledger->read(keylet::unchecked(*key));
-
471  if (!sleNode)
-
472  {
-
473  grpc::Status errorStatus{
-
474  grpc::StatusCode::NOT_FOUND, "object not found"};
-
475  return {response, errorStatus};
-
476  }
-
477  else
-
478  {
-
479  Serializer s;
-
480  sleNode->add(s);
-
481 
-
482  auto& stateObject = *response.mutable_ledger_object();
-
483  stateObject.set_data(s.peekData().data(), s.getLength());
-
484  stateObject.set_key(request.key());
-
485  *(response.mutable_ledger()) = request.ledger();
-
486  return {response, status};
-
487  }
-
488 }
-
489 } // namespace ripple
+
462  return jvResult;
+
463 }
+
464 
+
465 std::pair<org::xrpl::rpc::v1::GetLedgerEntryResponse, grpc::Status>
+
466 doLedgerEntryGrpc(
+
467  RPC::GRPCContext<org::xrpl::rpc::v1::GetLedgerEntryRequest>& context)
+
468 {
+
469  org::xrpl::rpc::v1::GetLedgerEntryRequest& request = context.params;
+
470  org::xrpl::rpc::v1::GetLedgerEntryResponse response;
+
471  grpc::Status status = grpc::Status::OK;
+
472 
+
473  std::shared_ptr<ReadView const> ledger;
+
474  if (auto status = RPC::ledgerFromRequest(ledger, context))
+
475  {
+
476  grpc::Status errorStatus;
+
477  if (status.toErrorCode() == rpcINVALID_PARAMS)
+
478  {
+
479  errorStatus = grpc::Status(
+
480  grpc::StatusCode::INVALID_ARGUMENT, status.message());
+
481  }
+
482  else
+
483  {
+
484  errorStatus =
+
485  grpc::Status(grpc::StatusCode::NOT_FOUND, status.message());
+
486  }
+
487  return {response, errorStatus};
+
488  }
+
489 
+
490  auto key = uint256::fromVoidChecked(request.key());
+
491  if (!key)
+
492  {
+
493  grpc::Status errorStatus{
+
494  grpc::StatusCode::INVALID_ARGUMENT, "index malformed"};
+
495  return {response, errorStatus};
+
496  }
+
497 
+
498  auto const sleNode = ledger->read(keylet::unchecked(*key));
+
499  if (!sleNode)
+
500  {
+
501  grpc::Status errorStatus{
+
502  grpc::StatusCode::NOT_FOUND, "object not found"};
+
503  return {response, errorStatus};
+
504  }
+
505  else
+
506  {
+
507  Serializer s;
+
508  sleNode->add(s);
+
509 
+
510  auto& stateObject = *response.mutable_ledger_object();
+
511  stateObject.set_data(s.peekData().data(), s.getLength());
+
512  stateObject.set_key(request.key());
+
513  *(response.mutable_ledger()) = request.ledger();
+
514  return {response, status};
+
515  }
+
516 }
+
517 } // namespace ripple
+
Definition: json_errors.h:27
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:304
bool to_currency(Currency &currency, std::string const &code)
Tries to convert a string to a Currency, returns true on success.
Definition: UintTypes.cpp:80
Definition: Context.h:53
@ ltTICKET
A ledger object which describes a ticket.
Definition: LedgerFormats.h:80
-
Json::Value doLedgerEntry(RPC::JsonContext &)
Definition: LedgerEntry.cpp:40
+
Json::Value doLedgerEntry(RPC::JsonContext &)
Definition: LedgerEntry.cpp:41
bool isObject() const
STL class.
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
@@ -588,7 +617,7 @@ $(function() {
static bool authorized(Port const &port, std::map< std::string, std::string > const &h)
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:134
@ ltESCROW
A ledger object describing a single escrow.
-
std::pair< org::xrpl::rpc::v1::GetLedgerEntryResponse, grpc::Status > doLedgerEntryGrpc(RPC::GRPCContext< org::xrpl::rpc::v1::GetLedgerEntryRequest > &context)
+
std::pair< org::xrpl::rpc::v1::GetLedgerEntryResponse, grpc::Status > doLedgerEntryGrpc(RPC::GRPCContext< org::xrpl::rpc::v1::GetLedgerEntryRequest > &context)
@ none
Keylet page(uint256 const &key, std::uint64_t index) noexcept
A page in a directory.
Definition: Indexes.cpp:310
Definition: Context.h:70
@@ -597,7 +626,7 @@ $(function() {
STL class.
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
-
Issue issueFromJson(Json::Value const &v)
Definition: Issue.cpp:77
+
Issue issueFromJson(Json::Value const &v)
Definition: Issue.cpp:78
Keylet line(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition: Indexes.cpp:194
Keylet unchecked(uint256 const &key) noexcept
Any ledger entry.
Definition: Indexes.cpp:298
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
diff --git a/LedgerRPC__test_8cpp_source.html b/LedgerRPC__test_8cpp_source.html index 8a244e6dc3..981ed1738b 100644 --- a/LedgerRPC__test_8cpp_source.html +++ b/LedgerRPC__test_8cpp_source.html @@ -1293,527 +1293,725 @@ $(function() {
1222 
1223  std::string const ledgerHash{to_string(env.closed()->info().hash)};
1224 
-
1225  // "features" is not an option supported by ledger_entry.
-
1226  Json::Value jvParams;
-
1227  jvParams[jss::api_version] = apiVersion;
-
1228  jvParams[jss::features] = ledgerHash;
-
1229  jvParams[jss::ledger_hash] = ledgerHash;
-
1230  Json::Value const jrr =
-
1231  env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
-
1232 
-
1233  if (apiVersion < 2u)
-
1234  checkErrorValue(jrr, "unknownOption", "");
-
1235  else
-
1236  checkErrorValue(jrr, "invalidParams", "");
-
1237  }
-
1238 
-
1243  void
-
1244  testLookupLedger()
-
1245  {
-
1246  testcase("Lookup ledger");
-
1247  using namespace test::jtx;
-
1248  Env env{*this, FeatureBitset{}}; // hashes requested below assume
-
1249  // no amendments
-
1250  env.fund(XRP(10000), "alice");
-
1251  env.close();
-
1252  env.fund(XRP(10000), "bob");
-
1253  env.close();
-
1254  env.fund(XRP(10000), "jim");
-
1255  env.close();
-
1256  env.fund(XRP(10000), "jill");
-
1257 
-
1258  {
-
1259  // access via the legacy ledger field, keyword index values
-
1260  Json::Value jvParams;
-
1261  jvParams[jss::ledger] = "closed";
-
1262  auto jrr = env.rpc(
-
1263  "json",
-
1264  "ledger",
-
1265  boost::lexical_cast<std::string>(jvParams))[jss::result];
-
1266  BEAST_EXPECT(jrr.isMember(jss::ledger));
-
1267  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
-
1268  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
-
1269 
-
1270  jvParams[jss::ledger] = "validated";
-
1271  jrr = env.rpc(
-
1272  "json",
-
1273  "ledger",
-
1274  boost::lexical_cast<std::string>(jvParams))[jss::result];
-
1275  BEAST_EXPECT(jrr.isMember(jss::ledger));
-
1276  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
-
1277  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
-
1278 
-
1279  jvParams[jss::ledger] = "current";
-
1280  jrr = env.rpc(
-
1281  "json",
-
1282  "ledger",
-
1283  boost::lexical_cast<std::string>(jvParams))[jss::result];
-
1284  BEAST_EXPECT(jrr.isMember(jss::ledger));
-
1285  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "6");
-
1286 
-
1287  // ask for a bad ledger keyword
-
1288  jvParams[jss::ledger] = "invalid";
-
1289  jrr = env.rpc(
-
1290  "json",
-
1291  "ledger",
-
1292  boost::lexical_cast<std::string>(jvParams))[jss::result];
-
1293  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
-
1294  BEAST_EXPECT(jrr[jss::error_message] == "ledgerIndexMalformed");
-
1295 
-
1296  // numeric index
-
1297  jvParams[jss::ledger] = 4;
-
1298  jrr = env.rpc(
-
1299  "json",
-
1300  "ledger",
-
1301  boost::lexical_cast<std::string>(jvParams))[jss::result];
-
1302  BEAST_EXPECT(jrr.isMember(jss::ledger));
-
1303  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
-
1304  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "4");
+
1225  auto makeParams = [&apiVersion](std::function<void(Json::Value&)> f) {
+
1226  Json::Value params;
+
1227  params[jss::api_version] = apiVersion;
+
1228  f(params);
+
1229  return params;
+
1230  };
+
1231  // "features" is not an option supported by ledger_entry.
+
1232  {
+
1233  auto const jvParams =
+
1234  makeParams([&ledgerHash](Json::Value& jvParams) {
+
1235  jvParams[jss::features] = ledgerHash;
+
1236  jvParams[jss::ledger_hash] = ledgerHash;
+
1237  });
+
1238  Json::Value const jrr = env.rpc(
+
1239  "json", "ledger_entry", to_string(jvParams))[jss::result];
+
1240 
+
1241  if (apiVersion < 2u)
+
1242  checkErrorValue(jrr, "unknownOption", "");
+
1243  else
+
1244  checkErrorValue(jrr, "invalidParams", "");
+
1245  }
+
1246  Json::Value const injectObject = []() {
+
1247  Json::Value obj(Json::objectValue);
+
1248  obj[jss::account] = "rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
+
1249  obj[jss::ledger_index] = "validated";
+
1250  return obj;
+
1251  }();
+
1252  Json::Value const injectArray = []() {
+
1253  Json::Value arr(Json::arrayValue);
+
1254  arr[0u] = "rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
+
1255  arr[1u] = "validated";
+
1256  return arr;
+
1257  }();
+
1258 
+
1259  // invalid input for fields that can handle an object, but can't handle
+
1260  // an array
+
1261  for (auto const& field :
+
1262  {jss::directory, jss::escrow, jss::offer, jss::ticket, jss::amm})
+
1263  {
+
1264  auto const jvParams =
+
1265  makeParams([&field, &injectArray](Json::Value& jvParams) {
+
1266  jvParams[field] = injectArray;
+
1267  });
+
1268 
+
1269  Json::Value const jrr = env.rpc(
+
1270  "json", "ledger_entry", to_string(jvParams))[jss::result];
+
1271 
+
1272  if (apiVersion < 2u)
+
1273  checkErrorValue(jrr, "internal", "Internal error.");
+
1274  else
+
1275  checkErrorValue(jrr, "invalidParams", "");
+
1276  }
+
1277  // Fields that can handle objects just fine
+
1278  for (auto const& field :
+
1279  {jss::directory, jss::escrow, jss::offer, jss::ticket, jss::amm})
+
1280  {
+
1281  auto const jvParams =
+
1282  makeParams([&field, &injectObject](Json::Value& jvParams) {
+
1283  jvParams[field] = injectObject;
+
1284  });
+
1285 
+
1286  Json::Value const jrr = env.rpc(
+
1287  "json", "ledger_entry", to_string(jvParams))[jss::result];
+
1288 
+
1289  checkErrorValue(jrr, "malformedRequest", "");
+
1290  }
+
1291 
+
1292  for (auto const& inject : {injectObject, injectArray})
+
1293  {
+
1294  // invalid input for fields that can't handle an object or an array
+
1295  for (auto const& field :
+
1296  {jss::index,
+
1297  jss::account_root,
+
1298  jss::check,
+
1299  jss::payment_channel})
+
1300  {
+
1301  auto const jvParams =
+
1302  makeParams([&field, &inject](Json::Value& jvParams) {
+
1303  jvParams[field] = inject;
+
1304  });
1305 
-
1306  // numeric index - out of range
-
1307  jvParams[jss::ledger] = 20;
-
1308  jrr = env.rpc(
-
1309  "json",
-
1310  "ledger",
-
1311  boost::lexical_cast<std::string>(jvParams))[jss::result];
-
1312  BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
-
1313  BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
-
1314  }
-
1315 
-
1316  {
-
1317  std::string const hash3{
-
1318  "E86DE7F3D7A4D9CE17EF7C8BA08A8F4D"
-
1319  "8F643B9552F0D895A31CDA78F541DE4E"};
-
1320  // access via the ledger_hash field
-
1321  Json::Value jvParams;
-
1322  jvParams[jss::ledger_hash] = hash3;
-
1323  auto jrr = env.rpc(
-
1324  "json",
-
1325  "ledger",
-
1326  boost::lexical_cast<std::string>(jvParams))[jss::result];
-
1327  BEAST_EXPECT(jrr.isMember(jss::ledger));
-
1328  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
-
1329  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "3");
-
1330 
-
1331  // extra leading hex chars in hash are not allowed
-
1332  jvParams[jss::ledger_hash] = "DEADBEEF" + hash3;
-
1333  jrr = env.rpc(
-
1334  "json",
-
1335  "ledger",
-
1336  boost::lexical_cast<std::string>(jvParams))[jss::result];
-
1337  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
-
1338  BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashMalformed");
-
1339 
-
1340  // request with non-string ledger_hash
-
1341  jvParams[jss::ledger_hash] = 2;
-
1342  jrr = env.rpc(
-
1343  "json",
-
1344  "ledger",
-
1345  boost::lexical_cast<std::string>(jvParams))[jss::result];
-
1346  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
-
1347  BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashNotString");
-
1348 
-
1349  // malformed (non hex) hash
-
1350  jvParams[jss::ledger_hash] =
-
1351  "2E81FC6EC0DD943197EGC7E3FBE9AE30"
-
1352  "7F2775F2F7485BB37307984C3C0F2340";
-
1353  jrr = env.rpc(
-
1354  "json",
-
1355  "ledger",
-
1356  boost::lexical_cast<std::string>(jvParams))[jss::result];
-
1357  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
-
1358  BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashMalformed");
-
1359 
-
1360  // properly formed, but just doesn't exist
-
1361  jvParams[jss::ledger_hash] =
-
1362  "8C3EEDB3124D92E49E75D81A8826A2E6"
-
1363  "5A75FD71FC3FD6F36FEB803C5F1D812D";
-
1364  jrr = env.rpc(
-
1365  "json",
-
1366  "ledger",
-
1367  boost::lexical_cast<std::string>(jvParams))[jss::result];
-
1368  BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
-
1369  BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
-
1370  }
-
1371 
-
1372  {
-
1373  // access via the ledger_index field, keyword index values
-
1374  Json::Value jvParams;
-
1375  jvParams[jss::ledger_index] = "closed";
-
1376  auto jrr = env.rpc(
-
1377  "json",
-
1378  "ledger",
-
1379  boost::lexical_cast<std::string>(jvParams))[jss::result];
-
1380  BEAST_EXPECT(jrr.isMember(jss::ledger));
-
1381  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
-
1382  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
-
1383  BEAST_EXPECT(jrr.isMember(jss::ledger_index));
-
1384 
-
1385  jvParams[jss::ledger_index] = "validated";
-
1386  jrr = env.rpc(
-
1387  "json",
-
1388  "ledger",
-
1389  boost::lexical_cast<std::string>(jvParams))[jss::result];
-
1390  BEAST_EXPECT(jrr.isMember(jss::ledger));
-
1391  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
-
1392  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
-
1393 
-
1394  jvParams[jss::ledger_index] = "current";
-
1395  jrr = env.rpc(
-
1396  "json",
-
1397  "ledger",
-
1398  boost::lexical_cast<std::string>(jvParams))[jss::result];
-
1399  BEAST_EXPECT(jrr.isMember(jss::ledger));
-
1400  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "6");
-
1401  BEAST_EXPECT(jrr.isMember(jss::ledger_current_index));
-
1402 
-
1403  // ask for a bad ledger keyword
-
1404  jvParams[jss::ledger_index] = "invalid";
-
1405  jrr = env.rpc(
-
1406  "json",
-
1407  "ledger",
-
1408  boost::lexical_cast<std::string>(jvParams))[jss::result];
-
1409  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
-
1410  BEAST_EXPECT(jrr[jss::error_message] == "ledgerIndexMalformed");
-
1411 
-
1412  // numeric index
-
1413  for (auto i : {1, 2, 3, 4, 5, 6})
-
1414  {
-
1415  jvParams[jss::ledger_index] = i;
-
1416  jrr = env.rpc(
-
1417  "json",
-
1418  "ledger",
-
1419  boost::lexical_cast<std::string>(jvParams))[jss::result];
-
1420  BEAST_EXPECT(jrr.isMember(jss::ledger));
-
1421  if (i < 6)
-
1422  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
-
1423  BEAST_EXPECT(
-
1424  jrr[jss::ledger][jss::ledger_index] == std::to_string(i));
-
1425  }
-
1426 
-
1427  // numeric index - out of range
-
1428  jvParams[jss::ledger_index] = 7;
-
1429  jrr = env.rpc(
-
1430  "json",
-
1431  "ledger",
-
1432  boost::lexical_cast<std::string>(jvParams))[jss::result];
-
1433  BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
-
1434  BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
-
1435  }
-
1436  }
-
1437 
-
1438  void
-
1439  testNoQueue()
-
1440  {
-
1441  testcase("Ledger with queueing disabled");
-
1442  using namespace test::jtx;
-
1443  Env env{*this};
-
1444 
-
1445  Json::Value jv;
-
1446  jv[jss::ledger_index] = "current";
-
1447  jv[jss::queue] = true;
-
1448  jv[jss::expand] = true;
-
1449 
-
1450  auto jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
-
1451  BEAST_EXPECT(!jrr.isMember(jss::queue_data));
-
1452  }
-
1453 
-
1454  void
-
1455  testQueue()
-
1456  {
-
1457  testcase("Ledger with Queued Transactions");
-
1458  using namespace test::jtx;
-
1459  Env env{*this, envconfig([](std::unique_ptr<Config> cfg) {
-
1460  auto& section = cfg->section("transaction_queue");
-
1461  section.set("minimum_txn_in_ledger_standalone", "3");
-
1462  section.set("normal_consensus_increase_percent", "0");
-
1463  return cfg;
-
1464  })};
-
1465 
-
1466  Json::Value jv;
-
1467  jv[jss::ledger_index] = "current";
-
1468  jv[jss::queue] = true;
-
1469  jv[jss::expand] = true;
-
1470 
-
1471  Account const alice{"alice"};
-
1472  Account const bob{"bob"};
-
1473  Account const charlie{"charlie"};
-
1474  Account const daria{"daria"};
-
1475  env.fund(XRP(10000), alice);
-
1476  env.fund(XRP(10000), bob);
-
1477  env.close();
-
1478  env.fund(XRP(10000), charlie);
-
1479  env.fund(XRP(10000), daria);
-
1480  env.close();
-
1481 
-
1482  auto jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
-
1483  BEAST_EXPECT(!jrr.isMember(jss::queue_data));
+
1306  Json::Value const jrr = env.rpc(
+
1307  "json", "ledger_entry", to_string(jvParams))[jss::result];
+
1308 
+
1309  if (apiVersion < 2u)
+
1310  checkErrorValue(jrr, "internal", "Internal error.");
+
1311  else
+
1312  checkErrorValue(jrr, "invalidParams", "");
+
1313  }
+
1314  // directory sub-fields
+
1315  for (auto const& field : {jss::dir_root, jss::owner})
+
1316  {
+
1317  auto const jvParams =
+
1318  makeParams([&field, &inject](Json::Value& jvParams) {
+
1319  jvParams[jss::directory][field] = inject;
+
1320  });
+
1321 
+
1322  Json::Value const jrr = env.rpc(
+
1323  "json", "ledger_entry", to_string(jvParams))[jss::result];
+
1324 
+
1325  if (apiVersion < 2u)
+
1326  checkErrorValue(jrr, "internal", "Internal error.");
+
1327  else
+
1328  checkErrorValue(jrr, "invalidParams", "");
+
1329  }
+
1330  // escrow sub-fields
+
1331  {
+
1332  auto const jvParams =
+
1333  makeParams([&inject](Json::Value& jvParams) {
+
1334  jvParams[jss::escrow][jss::owner] = inject;
+
1335  jvParams[jss::escrow][jss::seq] = 99;
+
1336  });
+
1337 
+
1338  Json::Value const jrr = env.rpc(
+
1339  "json", "ledger_entry", to_string(jvParams))[jss::result];
+
1340 
+
1341  if (apiVersion < 2u)
+
1342  checkErrorValue(jrr, "internal", "Internal error.");
+
1343  else
+
1344  checkErrorValue(jrr, "invalidParams", "");
+
1345  }
+
1346  // offer sub-fields
+
1347  {
+
1348  auto const jvParams =
+
1349  makeParams([&inject](Json::Value& jvParams) {
+
1350  jvParams[jss::offer][jss::account] = inject;
+
1351  jvParams[jss::offer][jss::seq] = 99;
+
1352  });
+
1353 
+
1354  Json::Value const jrr = env.rpc(
+
1355  "json", "ledger_entry", to_string(jvParams))[jss::result];
+
1356 
+
1357  if (apiVersion < 2u)
+
1358  checkErrorValue(jrr, "internal", "Internal error.");
+
1359  else
+
1360  checkErrorValue(jrr, "invalidParams", "");
+
1361  }
+
1362  // ripple_state sub-fields
+
1363  {
+
1364  auto const jvParams =
+
1365  makeParams([&inject](Json::Value& jvParams) {
+
1366  Json::Value rs(Json::objectValue);
+
1367  rs[jss::currency] = "FOO";
+
1368  rs[jss::accounts] = Json::Value(Json::arrayValue);
+
1369  rs[jss::accounts][0u] =
+
1370  "rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
+
1371  rs[jss::accounts][1u] =
+
1372  "rKssEq6pg1KbqEqAFnua5mFAL6Ggpsh2wv";
+
1373  rs[jss::currency] = inject;
+
1374  jvParams[jss::ripple_state] = std::move(rs);
+
1375  });
+
1376 
+
1377  Json::Value const jrr = env.rpc(
+
1378  "json", "ledger_entry", to_string(jvParams))[jss::result];
+
1379 
+
1380  if (apiVersion < 2u)
+
1381  checkErrorValue(jrr, "internal", "Internal error.");
+
1382  else
+
1383  checkErrorValue(jrr, "invalidParams", "");
+
1384  }
+
1385  // ticket sub-fields
+
1386  {
+
1387  auto const jvParams =
+
1388  makeParams([&inject](Json::Value& jvParams) {
+
1389  jvParams[jss::ticket][jss::account] = inject;
+
1390  jvParams[jss::ticket][jss::ticket_seq] = 99;
+
1391  });
+
1392 
+
1393  Json::Value const jrr = env.rpc(
+
1394  "json", "ledger_entry", to_string(jvParams))[jss::result];
+
1395 
+
1396  if (apiVersion < 2u)
+
1397  checkErrorValue(jrr, "internal", "Internal error.");
+
1398  else
+
1399  checkErrorValue(jrr, "invalidParams", "");
+
1400  }
+
1401 
+
1402  // Fields that can handle malformed inputs just fine
+
1403  for (auto const& field : {jss::nft_page, jss::deposit_preauth})
+
1404  {
+
1405  auto const jvParams =
+
1406  makeParams([&field, &inject](Json::Value& jvParams) {
+
1407  jvParams[field] = inject;
+
1408  });
+
1409 
+
1410  Json::Value const jrr = env.rpc(
+
1411  "json", "ledger_entry", to_string(jvParams))[jss::result];
+
1412 
+
1413  checkErrorValue(jrr, "malformedRequest", "");
+
1414  }
+
1415  // Subfields of deposit_preauth that can handle malformed inputs
+
1416  // fine
+
1417  for (auto const& field : {jss::owner, jss::authorized})
+
1418  {
+
1419  auto const jvParams =
+
1420  makeParams([&field, &inject](Json::Value& jvParams) {
+
1421  auto pa = Json::Value(Json::objectValue);
+
1422  pa[jss::owner] = "rhigTLJJyXXSRUyRCQtqi1NoAZZzZnS4KU";
+
1423  pa[jss::authorized] =
+
1424  "rKssEq6pg1KbqEqAFnua5mFAL6Ggpsh2wv";
+
1425  pa[field] = inject;
+
1426  jvParams[jss::deposit_preauth] = std::move(pa);
+
1427  });
+
1428 
+
1429  Json::Value const jrr = env.rpc(
+
1430  "json", "ledger_entry", to_string(jvParams))[jss::result];
+
1431 
+
1432  checkErrorValue(jrr, "malformedRequest", "");
+
1433  }
+
1434  }
+
1435  }
+
1436 
+
1441  void
+
1442  testLookupLedger()
+
1443  {
+
1444  testcase("Lookup ledger");
+
1445  using namespace test::jtx;
+
1446  Env env{*this, FeatureBitset{}}; // hashes requested below assume
+
1447  // no amendments
+
1448  env.fund(XRP(10000), "alice");
+
1449  env.close();
+
1450  env.fund(XRP(10000), "bob");
+
1451  env.close();
+
1452  env.fund(XRP(10000), "jim");
+
1453  env.close();
+
1454  env.fund(XRP(10000), "jill");
+
1455 
+
1456  {
+
1457  // access via the legacy ledger field, keyword index values
+
1458  Json::Value jvParams;
+
1459  jvParams[jss::ledger] = "closed";
+
1460  auto jrr = env.rpc(
+
1461  "json",
+
1462  "ledger",
+
1463  boost::lexical_cast<std::string>(jvParams))[jss::result];
+
1464  BEAST_EXPECT(jrr.isMember(jss::ledger));
+
1465  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
+
1466  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
+
1467 
+
1468  jvParams[jss::ledger] = "validated";
+
1469  jrr = env.rpc(
+
1470  "json",
+
1471  "ledger",
+
1472  boost::lexical_cast<std::string>(jvParams))[jss::result];
+
1473  BEAST_EXPECT(jrr.isMember(jss::ledger));
+
1474  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
+
1475  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
+
1476 
+
1477  jvParams[jss::ledger] = "current";
+
1478  jrr = env.rpc(
+
1479  "json",
+
1480  "ledger",
+
1481  boost::lexical_cast<std::string>(jvParams))[jss::result];
+
1482  BEAST_EXPECT(jrr.isMember(jss::ledger));
+
1483  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "6");
1484 
-
1485  // Fill the open ledger
-
1486  for (;;)
-
1487  {
-
1488  auto metrics = env.app().getTxQ().getMetrics(*env.current());
-
1489  if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
-
1490  break;
-
1491  env(noop(alice));
-
1492  }
+
1485  // ask for a bad ledger keyword
+
1486  jvParams[jss::ledger] = "invalid";
+
1487  jrr = env.rpc(
+
1488  "json",
+
1489  "ledger",
+
1490  boost::lexical_cast<std::string>(jvParams))[jss::result];
+
1491  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
+
1492  BEAST_EXPECT(jrr[jss::error_message] == "ledgerIndexMalformed");
1493 
-
1494  BEAST_EXPECT(env.current()->info().seq == 5);
-
1495  // Put some txs in the queue
-
1496  // Alice
-
1497  auto aliceSeq = env.seq(alice);
-
1498  env(pay(alice, "george", XRP(1000)),
-
1499  json(R"({"LastLedgerSequence":7})"),
-
1500  ter(terQUEUED));
-
1501  env(offer(alice, XRP(50000), alice["USD"](5000)),
-
1502  seq(aliceSeq + 1),
-
1503  ter(terQUEUED));
-
1504  env(noop(alice), seq(aliceSeq + 2), ter(terQUEUED));
-
1505  // Bob
-
1506  auto batch = [&env](Account a) {
-
1507  auto aSeq = env.seq(a);
-
1508  // Enough fee to get in front of alice in the queue
-
1509  for (int i = 0; i < 10; ++i)
-
1510  {
-
1511  env(noop(a), fee(1000 + i), seq(aSeq + i), ter(terQUEUED));
-
1512  }
-
1513  };
-
1514  batch(bob);
-
1515  // Charlie
-
1516  batch(charlie);
-
1517  // Daria
-
1518  batch(daria);
-
1519 
-
1520  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
-
1521  BEAST_EXPECT(jrr[jss::queue_data].size() == 33);
-
1522 
-
1523  // Close enough ledgers so that alice's first tx expires.
-
1524  env.close();
-
1525  env.close();
-
1526  env.close();
-
1527  BEAST_EXPECT(env.current()->info().seq == 8);
+
1494  // numeric index
+
1495  jvParams[jss::ledger] = 4;
+
1496  jrr = env.rpc(
+
1497  "json",
+
1498  "ledger",
+
1499  boost::lexical_cast<std::string>(jvParams))[jss::result];
+
1500  BEAST_EXPECT(jrr.isMember(jss::ledger));
+
1501  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
+
1502  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "4");
+
1503 
+
1504  // numeric index - out of range
+
1505  jvParams[jss::ledger] = 20;
+
1506  jrr = env.rpc(
+
1507  "json",
+
1508  "ledger",
+
1509  boost::lexical_cast<std::string>(jvParams))[jss::result];
+
1510  BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
+
1511  BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
+
1512  }
+
1513 
+
1514  {
+
1515  std::string const hash3{
+
1516  "E86DE7F3D7A4D9CE17EF7C8BA08A8F4D"
+
1517  "8F643B9552F0D895A31CDA78F541DE4E"};
+
1518  // access via the ledger_hash field
+
1519  Json::Value jvParams;
+
1520  jvParams[jss::ledger_hash] = hash3;
+
1521  auto jrr = env.rpc(
+
1522  "json",
+
1523  "ledger",
+
1524  boost::lexical_cast<std::string>(jvParams))[jss::result];
+
1525  BEAST_EXPECT(jrr.isMember(jss::ledger));
+
1526  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
+
1527  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "3");
1528 
-
1529  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
-
1530  BEAST_EXPECT(jrr[jss::queue_data].size() == 11);
-
1531 
-
1532  env.close();
-
1533 
-
1534  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
-
1535  const std::string txid0 = [&]() {
-
1536  auto const& parentHash = env.current()->info().parentHash;
-
1537  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
-
1538  {
-
1539  const std::string txid1 = [&]() {
-
1540  auto const& txj = jrr[jss::queue_data][1u];
-
1541  BEAST_EXPECT(txj[jss::account] == alice.human());
-
1542  BEAST_EXPECT(txj[jss::fee_level] == "256");
-
1543  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
-
1544  BEAST_EXPECT(txj["retries_remaining"] == 10);
-
1545  BEAST_EXPECT(txj.isMember(jss::tx));
-
1546  auto const& tx = txj[jss::tx];
-
1547  BEAST_EXPECT(tx[jss::Account] == alice.human());
-
1548  BEAST_EXPECT(tx[jss::TransactionType] == jss::AccountSet);
-
1549  return tx[jss::hash].asString();
-
1550  }();
-
1551 
-
1552  auto const& txj = jrr[jss::queue_data][0u];
-
1553  BEAST_EXPECT(txj[jss::account] == alice.human());
-
1554  BEAST_EXPECT(txj[jss::fee_level] == "256");
-
1555  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
-
1556  BEAST_EXPECT(txj["retries_remaining"] == 10);
-
1557  BEAST_EXPECT(txj.isMember(jss::tx));
-
1558  auto const& tx = txj[jss::tx];
-
1559  BEAST_EXPECT(tx[jss::Account] == alice.human());
-
1560  BEAST_EXPECT(tx[jss::TransactionType] == jss::OfferCreate);
-
1561  const auto txid0 = tx[jss::hash].asString();
-
1562  uint256 tx0, tx1;
-
1563  BEAST_EXPECT(tx0.parseHex(txid0));
-
1564  BEAST_EXPECT(tx1.parseHex(txid1));
-
1565  BEAST_EXPECT((tx0 ^ parentHash) < (tx1 ^ parentHash));
-
1566  return txid0;
-
1567  }
-
1568  return std::string{};
-
1569  }();
-
1570 
-
1571  env.close();
-
1572 
-
1573  jv[jss::expand] = false;
-
1574 
-
1575  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
-
1576  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
-
1577  {
-
1578  auto const& parentHash = env.current()->info().parentHash;
-
1579  auto const txid1 = [&]() {
-
1580  auto const& txj = jrr[jss::queue_data][1u];
-
1581  BEAST_EXPECT(txj[jss::account] == alice.human());
-
1582  BEAST_EXPECT(txj[jss::fee_level] == "256");
-
1583  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
-
1584  BEAST_EXPECT(txj.isMember(jss::tx));
-
1585  return txj[jss::tx].asString();
-
1586  }();
-
1587  auto const& txj = jrr[jss::queue_data][0u];
-
1588  BEAST_EXPECT(txj[jss::account] == alice.human());
-
1589  BEAST_EXPECT(txj[jss::fee_level] == "256");
-
1590  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
-
1591  BEAST_EXPECT(txj["retries_remaining"] == 9);
-
1592  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
-
1593  BEAST_EXPECT(txj.isMember(jss::tx));
-
1594  BEAST_EXPECT(txj[jss::tx] == txid0);
-
1595  uint256 tx0, tx1;
-
1596  BEAST_EXPECT(tx0.parseHex(txid0));
-
1597  BEAST_EXPECT(tx1.parseHex(txid1));
-
1598  BEAST_EXPECT((tx0 ^ parentHash) < (tx1 ^ parentHash));
-
1599  }
+
1529  // extra leading hex chars in hash are not allowed
+
1530  jvParams[jss::ledger_hash] = "DEADBEEF" + hash3;
+
1531  jrr = env.rpc(
+
1532  "json",
+
1533  "ledger",
+
1534  boost::lexical_cast<std::string>(jvParams))[jss::result];
+
1535  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
+
1536  BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashMalformed");
+
1537 
+
1538  // request with non-string ledger_hash
+
1539  jvParams[jss::ledger_hash] = 2;
+
1540  jrr = env.rpc(
+
1541  "json",
+
1542  "ledger",
+
1543  boost::lexical_cast<std::string>(jvParams))[jss::result];
+
1544  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
+
1545  BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashNotString");
+
1546 
+
1547  // malformed (non hex) hash
+
1548  jvParams[jss::ledger_hash] =
+
1549  "2E81FC6EC0DD943197EGC7E3FBE9AE30"
+
1550  "7F2775F2F7485BB37307984C3C0F2340";
+
1551  jrr = env.rpc(
+
1552  "json",
+
1553  "ledger",
+
1554  boost::lexical_cast<std::string>(jvParams))[jss::result];
+
1555  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
+
1556  BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashMalformed");
+
1557 
+
1558  // properly formed, but just doesn't exist
+
1559  jvParams[jss::ledger_hash] =
+
1560  "8C3EEDB3124D92E49E75D81A8826A2E6"
+
1561  "5A75FD71FC3FD6F36FEB803C5F1D812D";
+
1562  jrr = env.rpc(
+
1563  "json",
+
1564  "ledger",
+
1565  boost::lexical_cast<std::string>(jvParams))[jss::result];
+
1566  BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
+
1567  BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
+
1568  }
+
1569 
+
1570  {
+
1571  // access via the ledger_index field, keyword index values
+
1572  Json::Value jvParams;
+
1573  jvParams[jss::ledger_index] = "closed";
+
1574  auto jrr = env.rpc(
+
1575  "json",
+
1576  "ledger",
+
1577  boost::lexical_cast<std::string>(jvParams))[jss::result];
+
1578  BEAST_EXPECT(jrr.isMember(jss::ledger));
+
1579  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
+
1580  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
+
1581  BEAST_EXPECT(jrr.isMember(jss::ledger_index));
+
1582 
+
1583  jvParams[jss::ledger_index] = "validated";
+
1584  jrr = env.rpc(
+
1585  "json",
+
1586  "ledger",
+
1587  boost::lexical_cast<std::string>(jvParams))[jss::result];
+
1588  BEAST_EXPECT(jrr.isMember(jss::ledger));
+
1589  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
+
1590  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
+
1591 
+
1592  jvParams[jss::ledger_index] = "current";
+
1593  jrr = env.rpc(
+
1594  "json",
+
1595  "ledger",
+
1596  boost::lexical_cast<std::string>(jvParams))[jss::result];
+
1597  BEAST_EXPECT(jrr.isMember(jss::ledger));
+
1598  BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "6");
+
1599  BEAST_EXPECT(jrr.isMember(jss::ledger_current_index));
1600 
-
1601  env.close();
-
1602 
-
1603  jv[jss::expand] = true;
-
1604  jv[jss::binary] = true;
-
1605 
-
1606  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
-
1607  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
-
1608  {
-
1609  auto const& txj = jrr[jss::queue_data][1u];
-
1610  BEAST_EXPECT(txj[jss::account] == alice.human());
-
1611  BEAST_EXPECT(txj[jss::fee_level] == "256");
-
1612  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
-
1613  BEAST_EXPECT(txj["retries_remaining"] == 8);
-
1614  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
-
1615  BEAST_EXPECT(txj.isMember(jss::tx));
-
1616  BEAST_EXPECT(txj[jss::tx].isMember(jss::tx_blob));
-
1617 
-
1618  auto const& txj2 = jrr[jss::queue_data][0u];
-
1619  BEAST_EXPECT(txj2[jss::account] == alice.human());
-
1620  BEAST_EXPECT(txj2[jss::fee_level] == "256");
-
1621  BEAST_EXPECT(txj2["preflight_result"] == "tesSUCCESS");
-
1622  BEAST_EXPECT(txj2["retries_remaining"] == 10);
-
1623  BEAST_EXPECT(!txj2.isMember("last_result"));
-
1624  BEAST_EXPECT(txj2.isMember(jss::tx));
-
1625  BEAST_EXPECT(txj2[jss::tx].isMember(jss::tx_blob));
-
1626  }
-
1627 
-
1628  for (int i = 0; i != 9; ++i)
-
1629  {
-
1630  env.close();
-
1631  }
-
1632 
-
1633  jv[jss::expand] = false;
-
1634  jv[jss::binary] = false;
+
1601  // ask for a bad ledger keyword
+
1602  jvParams[jss::ledger_index] = "invalid";
+
1603  jrr = env.rpc(
+
1604  "json",
+
1605  "ledger",
+
1606  boost::lexical_cast<std::string>(jvParams))[jss::result];
+
1607  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
+
1608  BEAST_EXPECT(jrr[jss::error_message] == "ledgerIndexMalformed");
+
1609 
+
1610  // numeric index
+
1611  for (auto i : {1, 2, 3, 4, 5, 6})
+
1612  {
+
1613  jvParams[jss::ledger_index] = i;
+
1614  jrr = env.rpc(
+
1615  "json",
+
1616  "ledger",
+
1617  boost::lexical_cast<std::string>(jvParams))[jss::result];
+
1618  BEAST_EXPECT(jrr.isMember(jss::ledger));
+
1619  if (i < 6)
+
1620  BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
+
1621  BEAST_EXPECT(
+
1622  jrr[jss::ledger][jss::ledger_index] == std::to_string(i));
+
1623  }
+
1624 
+
1625  // numeric index - out of range
+
1626  jvParams[jss::ledger_index] = 7;
+
1627  jrr = env.rpc(
+
1628  "json",
+
1629  "ledger",
+
1630  boost::lexical_cast<std::string>(jvParams))[jss::result];
+
1631  BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
+
1632  BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
+
1633  }
+
1634  }
1635 
-
1636  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
-
1637  const std::string txid2 = [&]() {
-
1638  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
-
1639  {
-
1640  auto const& txj = jrr[jss::queue_data][0u];
-
1641  BEAST_EXPECT(txj[jss::account] == alice.human());
-
1642  BEAST_EXPECT(txj[jss::fee_level] == "256");
-
1643  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
-
1644  BEAST_EXPECT(txj["retries_remaining"] == 1);
-
1645  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
-
1646  BEAST_EXPECT(txj.isMember(jss::tx));
-
1647  BEAST_EXPECT(txj[jss::tx] != txid0);
-
1648  return txj[jss::tx].asString();
-
1649  }
-
1650  return std::string{};
-
1651  }();
-
1652 
-
1653  jv[jss::full] = true;
-
1654 
-
1655  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
-
1656  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
-
1657  {
-
1658  auto const& txj = jrr[jss::queue_data][0u];
-
1659  BEAST_EXPECT(txj[jss::account] == alice.human());
-
1660  BEAST_EXPECT(txj[jss::fee_level] == "256");
-
1661  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
-
1662  BEAST_EXPECT(txj["retries_remaining"] == 1);
-
1663  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
-
1664  BEAST_EXPECT(txj.isMember(jss::tx));
-
1665  auto const& tx = txj[jss::tx];
-
1666  BEAST_EXPECT(tx[jss::Account] == alice.human());
-
1667  BEAST_EXPECT(tx[jss::TransactionType] == jss::AccountSet);
-
1668  BEAST_EXPECT(tx[jss::hash] == txid2);
-
1669  }
-
1670  }
-
1671 
-
1672  void
-
1673  testLedgerAccountsOption()
-
1674  {
-
1675  testcase("Ledger Request, Accounts Hashes");
-
1676  using namespace test::jtx;
-
1677 
-
1678  Env env{*this};
+
1636  void
+
1637  testNoQueue()
+
1638  {
+
1639  testcase("Ledger with queueing disabled");
+
1640  using namespace test::jtx;
+
1641  Env env{*this};
+
1642 
+
1643  Json::Value jv;
+
1644  jv[jss::ledger_index] = "current";
+
1645  jv[jss::queue] = true;
+
1646  jv[jss::expand] = true;
+
1647 
+
1648  auto jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
+
1649  BEAST_EXPECT(!jrr.isMember(jss::queue_data));
+
1650  }
+
1651 
+
1652  void
+
1653  testQueue()
+
1654  {
+
1655  testcase("Ledger with Queued Transactions");
+
1656  using namespace test::jtx;
+
1657  Env env{*this, envconfig([](std::unique_ptr<Config> cfg) {
+
1658  auto& section = cfg->section("transaction_queue");
+
1659  section.set("minimum_txn_in_ledger_standalone", "3");
+
1660  section.set("normal_consensus_increase_percent", "0");
+
1661  return cfg;
+
1662  })};
+
1663 
+
1664  Json::Value jv;
+
1665  jv[jss::ledger_index] = "current";
+
1666  jv[jss::queue] = true;
+
1667  jv[jss::expand] = true;
+
1668 
+
1669  Account const alice{"alice"};
+
1670  Account const bob{"bob"};
+
1671  Account const charlie{"charlie"};
+
1672  Account const daria{"daria"};
+
1673  env.fund(XRP(10000), alice);
+
1674  env.fund(XRP(10000), bob);
+
1675  env.close();
+
1676  env.fund(XRP(10000), charlie);
+
1677  env.fund(XRP(10000), daria);
+
1678  env.close();
1679 
-
1680  env.close();
-
1681 
-
1682  std::string index;
-
1683  {
-
1684  Json::Value jvParams;
-
1685  jvParams[jss::ledger_index] = 3u;
-
1686  jvParams[jss::accounts] = true;
-
1687  jvParams[jss::expand] = true;
-
1688  jvParams[jss::type] = "hashes";
-
1689  auto const jrr =
-
1690  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
-
1691  BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
-
1692  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
-
1693  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 1u);
-
1694  BEAST_EXPECT(
-
1695  jrr[jss::ledger][jss::accountState][0u]["LedgerEntryType"] ==
-
1696  jss::LedgerHashes);
-
1697  index = jrr[jss::ledger][jss::accountState][0u]["index"].asString();
-
1698  }
-
1699  {
-
1700  Json::Value jvParams;
-
1701  jvParams[jss::ledger_index] = 3u;
-
1702  jvParams[jss::accounts] = true;
-
1703  jvParams[jss::expand] = false;
-
1704  jvParams[jss::type] = "hashes";
-
1705  auto const jrr =
-
1706  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
-
1707  BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
-
1708  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
-
1709  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 1u);
-
1710  BEAST_EXPECT(jrr[jss::ledger][jss::accountState][0u] == index);
-
1711  }
-
1712  }
-
1713 
-
1714 public:
-
1715  void
-
1716  run() override
-
1717  {
-
1718  testLedgerRequest();
-
1719  testBadInput();
-
1720  testLedgerCurrent();
-
1721  testMissingLedgerEntryLedgerHash();
-
1722  testLedgerFull();
-
1723  testLedgerFullNonAdmin();
-
1724  testLedgerAccounts();
-
1725  testLedgerEntryAccountRoot();
-
1726  testLedgerEntryCheck();
-
1727  testLedgerEntryDepositPreauth();
-
1728  testLedgerEntryDirectory();
-
1729  testLedgerEntryEscrow();
-
1730  testLedgerEntryOffer();
-
1731  testLedgerEntryPayChan();
-
1732  testLedgerEntryRippleState();
-
1733  testLedgerEntryTicket();
-
1734  testLookupLedger();
-
1735  testNoQueue();
-
1736  testQueue();
-
1737  testLedgerAccountsOption();
-
1738 
-
1739  test::jtx::forAllApiVersions(std::bind_front(
-
1740  &LedgerRPC_test::testLedgerEntryInvalidParams, this));
-
1741  }
-
1742 };
-
1743 
-
1744 BEAST_DEFINE_TESTSUITE(LedgerRPC, app, ripple);
-
1745 
-
1746 } // namespace ripple
+
1680  auto jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
+
1681  BEAST_EXPECT(!jrr.isMember(jss::queue_data));
+
1682 
+
1683  // Fill the open ledger
+
1684  for (;;)
+
1685  {
+
1686  auto metrics = env.app().getTxQ().getMetrics(*env.current());
+
1687  if (metrics.openLedgerFeeLevel > metrics.minProcessingFeeLevel)
+
1688  break;
+
1689  env(noop(alice));
+
1690  }
+
1691 
+
1692  BEAST_EXPECT(env.current()->info().seq == 5);
+
1693  // Put some txs in the queue
+
1694  // Alice
+
1695  auto aliceSeq = env.seq(alice);
+
1696  env(pay(alice, "george", XRP(1000)),
+
1697  json(R"({"LastLedgerSequence":7})"),
+
1698  ter(terQUEUED));
+
1699  env(offer(alice, XRP(50000), alice["USD"](5000)),
+
1700  seq(aliceSeq + 1),
+
1701  ter(terQUEUED));
+
1702  env(noop(alice), seq(aliceSeq + 2), ter(terQUEUED));
+
1703  // Bob
+
1704  auto batch = [&env](Account a) {
+
1705  auto aSeq = env.seq(a);
+
1706  // Enough fee to get in front of alice in the queue
+
1707  for (int i = 0; i < 10; ++i)
+
1708  {
+
1709  env(noop(a), fee(1000 + i), seq(aSeq + i), ter(terQUEUED));
+
1710  }
+
1711  };
+
1712  batch(bob);
+
1713  // Charlie
+
1714  batch(charlie);
+
1715  // Daria
+
1716  batch(daria);
+
1717 
+
1718  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
+
1719  BEAST_EXPECT(jrr[jss::queue_data].size() == 33);
+
1720 
+
1721  // Close enough ledgers so that alice's first tx expires.
+
1722  env.close();
+
1723  env.close();
+
1724  env.close();
+
1725  BEAST_EXPECT(env.current()->info().seq == 8);
+
1726 
+
1727  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
+
1728  BEAST_EXPECT(jrr[jss::queue_data].size() == 11);
+
1729 
+
1730  env.close();
+
1731 
+
1732  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
+
1733  const std::string txid0 = [&]() {
+
1734  auto const& parentHash = env.current()->info().parentHash;
+
1735  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
+
1736  {
+
1737  const std::string txid1 = [&]() {
+
1738  auto const& txj = jrr[jss::queue_data][1u];
+
1739  BEAST_EXPECT(txj[jss::account] == alice.human());
+
1740  BEAST_EXPECT(txj[jss::fee_level] == "256");
+
1741  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
+
1742  BEAST_EXPECT(txj["retries_remaining"] == 10);
+
1743  BEAST_EXPECT(txj.isMember(jss::tx));
+
1744  auto const& tx = txj[jss::tx];
+
1745  BEAST_EXPECT(tx[jss::Account] == alice.human());
+
1746  BEAST_EXPECT(tx[jss::TransactionType] == jss::AccountSet);
+
1747  return tx[jss::hash].asString();
+
1748  }();
+
1749 
+
1750  auto const& txj = jrr[jss::queue_data][0u];
+
1751  BEAST_EXPECT(txj[jss::account] == alice.human());
+
1752  BEAST_EXPECT(txj[jss::fee_level] == "256");
+
1753  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
+
1754  BEAST_EXPECT(txj["retries_remaining"] == 10);
+
1755  BEAST_EXPECT(txj.isMember(jss::tx));
+
1756  auto const& tx = txj[jss::tx];
+
1757  BEAST_EXPECT(tx[jss::Account] == alice.human());
+
1758  BEAST_EXPECT(tx[jss::TransactionType] == jss::OfferCreate);
+
1759  const auto txid0 = tx[jss::hash].asString();
+
1760  uint256 tx0, tx1;
+
1761  BEAST_EXPECT(tx0.parseHex(txid0));
+
1762  BEAST_EXPECT(tx1.parseHex(txid1));
+
1763  BEAST_EXPECT((tx0 ^ parentHash) < (tx1 ^ parentHash));
+
1764  return txid0;
+
1765  }
+
1766  return std::string{};
+
1767  }();
+
1768 
+
1769  env.close();
+
1770 
+
1771  jv[jss::expand] = false;
+
1772 
+
1773  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
+
1774  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
+
1775  {
+
1776  auto const& parentHash = env.current()->info().parentHash;
+
1777  auto const txid1 = [&]() {
+
1778  auto const& txj = jrr[jss::queue_data][1u];
+
1779  BEAST_EXPECT(txj[jss::account] == alice.human());
+
1780  BEAST_EXPECT(txj[jss::fee_level] == "256");
+
1781  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
+
1782  BEAST_EXPECT(txj.isMember(jss::tx));
+
1783  return txj[jss::tx].asString();
+
1784  }();
+
1785  auto const& txj = jrr[jss::queue_data][0u];
+
1786  BEAST_EXPECT(txj[jss::account] == alice.human());
+
1787  BEAST_EXPECT(txj[jss::fee_level] == "256");
+
1788  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
+
1789  BEAST_EXPECT(txj["retries_remaining"] == 9);
+
1790  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
+
1791  BEAST_EXPECT(txj.isMember(jss::tx));
+
1792  BEAST_EXPECT(txj[jss::tx] == txid0);
+
1793  uint256 tx0, tx1;
+
1794  BEAST_EXPECT(tx0.parseHex(txid0));
+
1795  BEAST_EXPECT(tx1.parseHex(txid1));
+
1796  BEAST_EXPECT((tx0 ^ parentHash) < (tx1 ^ parentHash));
+
1797  }
+
1798 
+
1799  env.close();
+
1800 
+
1801  jv[jss::expand] = true;
+
1802  jv[jss::binary] = true;
+
1803 
+
1804  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
+
1805  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 2))
+
1806  {
+
1807  auto const& txj = jrr[jss::queue_data][1u];
+
1808  BEAST_EXPECT(txj[jss::account] == alice.human());
+
1809  BEAST_EXPECT(txj[jss::fee_level] == "256");
+
1810  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
+
1811  BEAST_EXPECT(txj["retries_remaining"] == 8);
+
1812  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
+
1813  BEAST_EXPECT(txj.isMember(jss::tx));
+
1814  BEAST_EXPECT(txj[jss::tx].isMember(jss::tx_blob));
+
1815 
+
1816  auto const& txj2 = jrr[jss::queue_data][0u];
+
1817  BEAST_EXPECT(txj2[jss::account] == alice.human());
+
1818  BEAST_EXPECT(txj2[jss::fee_level] == "256");
+
1819  BEAST_EXPECT(txj2["preflight_result"] == "tesSUCCESS");
+
1820  BEAST_EXPECT(txj2["retries_remaining"] == 10);
+
1821  BEAST_EXPECT(!txj2.isMember("last_result"));
+
1822  BEAST_EXPECT(txj2.isMember(jss::tx));
+
1823  BEAST_EXPECT(txj2[jss::tx].isMember(jss::tx_blob));
+
1824  }
+
1825 
+
1826  for (int i = 0; i != 9; ++i)
+
1827  {
+
1828  env.close();
+
1829  }
+
1830 
+
1831  jv[jss::expand] = false;
+
1832  jv[jss::binary] = false;
+
1833 
+
1834  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
+
1835  const std::string txid2 = [&]() {
+
1836  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
+
1837  {
+
1838  auto const& txj = jrr[jss::queue_data][0u];
+
1839  BEAST_EXPECT(txj[jss::account] == alice.human());
+
1840  BEAST_EXPECT(txj[jss::fee_level] == "256");
+
1841  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
+
1842  BEAST_EXPECT(txj["retries_remaining"] == 1);
+
1843  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
+
1844  BEAST_EXPECT(txj.isMember(jss::tx));
+
1845  BEAST_EXPECT(txj[jss::tx] != txid0);
+
1846  return txj[jss::tx].asString();
+
1847  }
+
1848  return std::string{};
+
1849  }();
+
1850 
+
1851  jv[jss::full] = true;
+
1852 
+
1853  jrr = env.rpc("json", "ledger", to_string(jv))[jss::result];
+
1854  if (BEAST_EXPECT(jrr[jss::queue_data].size() == 1))
+
1855  {
+
1856  auto const& txj = jrr[jss::queue_data][0u];
+
1857  BEAST_EXPECT(txj[jss::account] == alice.human());
+
1858  BEAST_EXPECT(txj[jss::fee_level] == "256");
+
1859  BEAST_EXPECT(txj["preflight_result"] == "tesSUCCESS");
+
1860  BEAST_EXPECT(txj["retries_remaining"] == 1);
+
1861  BEAST_EXPECT(txj["last_result"] == "terPRE_SEQ");
+
1862  BEAST_EXPECT(txj.isMember(jss::tx));
+
1863  auto const& tx = txj[jss::tx];
+
1864  BEAST_EXPECT(tx[jss::Account] == alice.human());
+
1865  BEAST_EXPECT(tx[jss::TransactionType] == jss::AccountSet);
+
1866  BEAST_EXPECT(tx[jss::hash] == txid2);
+
1867  }
+
1868  }
+
1869 
+
1870  void
+
1871  testLedgerAccountsOption()
+
1872  {
+
1873  testcase("Ledger Request, Accounts Hashes");
+
1874  using namespace test::jtx;
+
1875 
+
1876  Env env{*this};
+
1877 
+
1878  env.close();
+
1879 
+
1880  std::string index;
+
1881  {
+
1882  Json::Value jvParams;
+
1883  jvParams[jss::ledger_index] = 3u;
+
1884  jvParams[jss::accounts] = true;
+
1885  jvParams[jss::expand] = true;
+
1886  jvParams[jss::type] = "hashes";
+
1887  auto const jrr =
+
1888  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
+
1889  BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
+
1890  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
+
1891  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 1u);
+
1892  BEAST_EXPECT(
+
1893  jrr[jss::ledger][jss::accountState][0u]["LedgerEntryType"] ==
+
1894  jss::LedgerHashes);
+
1895  index = jrr[jss::ledger][jss::accountState][0u]["index"].asString();
+
1896  }
+
1897  {
+
1898  Json::Value jvParams;
+
1899  jvParams[jss::ledger_index] = 3u;
+
1900  jvParams[jss::accounts] = true;
+
1901  jvParams[jss::expand] = false;
+
1902  jvParams[jss::type] = "hashes";
+
1903  auto const jrr =
+
1904  env.rpc("json", "ledger", to_string(jvParams))[jss::result];
+
1905  BEAST_EXPECT(jrr[jss::ledger].isMember(jss::accountState));
+
1906  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].isArray());
+
1907  BEAST_EXPECT(jrr[jss::ledger][jss::accountState].size() == 1u);
+
1908  BEAST_EXPECT(jrr[jss::ledger][jss::accountState][0u] == index);
+
1909  }
+
1910  }
+
1911 
+
1912 public:
+
1913  void
+
1914  run() override
+
1915  {
+
1916  testLedgerRequest();
+
1917  testBadInput();
+
1918  testLedgerCurrent();
+
1919  testMissingLedgerEntryLedgerHash();
+
1920  testLedgerFull();
+
1921  testLedgerFullNonAdmin();
+
1922  testLedgerAccounts();
+
1923  testLedgerEntryAccountRoot();
+
1924  testLedgerEntryCheck();
+
1925  testLedgerEntryDepositPreauth();
+
1926  testLedgerEntryDirectory();
+
1927  testLedgerEntryEscrow();
+
1928  testLedgerEntryOffer();
+
1929  testLedgerEntryPayChan();
+
1930  testLedgerEntryRippleState();
+
1931  testLedgerEntryTicket();
+
1932  testLookupLedger();
+
1933  testNoQueue();
+
1934  testQueue();
+
1935  testLedgerAccountsOption();
+
1936 
+
1937  test::jtx::forAllApiVersions(std::bind_front(
+
1938  &LedgerRPC_test::testLedgerEntryInvalidParams, this));
+
1939  }
+
1940 };
+
1941 
+
1942 BEAST_DEFINE_TESTSUITE(LedgerRPC, app, ripple);
+
1943 
+
1944 } // namespace ripple
void testLedgerEntryRippleState()
-
void testLookupLedger()
ledger RPC requests as a way to drive input options to lookupLedger.
+
void testLookupLedger()
ledger RPC requests as a way to drive input options to lookupLedger.
const SF_AMOUNT sfSendMax
STL class.
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
@@ -1822,11 +2020,12 @@ $(function() {
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
void testLedgerEntryOffer()
-
void testNoQueue()
+
void testNoQueue()
void testLedgerEntryInvalidParams(unsigned int apiVersion)
const SF_UINT32 sfTicketSequence
void forAllApiVersions(VersionedTestCallable auto... testCallable)
Definition: Env.h:743
T bind_front(T... args)
+
const Json::StaticString jsonName
Definition: SField.h:139
uint256 getTicketIndex(AccountID const &account, std::uint32_t ticketSeq)
Definition: Indexes.cpp:116
@@ -1835,7 +2034,7 @@ $(function() {
const SF_VECTOR256 sfIndexes
uint256 key
Definition: Keylet.h:40
-
void testLedgerAccountsOption()
+
void testLedgerAccountsOption()
void testLedgerFullNonAdmin()
const SF_UINT32 sfSettleDelay
void testLedgerFull()
@@ -1846,7 +2045,7 @@ $(function() {
std::string makeBadAddress(std::string good)
void testBadInput()
@ none
-
void testQueue()
+
void testQueue()
void testLedgerEntryAccountRoot()
T to_string(T... args)
Definition: STAmount.h:45
@@ -1857,7 +2056,7 @@ $(function() {
const SF_ACCOUNT sfAuthorize
const SF_AMOUNT sfHighLimit
-
void run() override
+
void run() override
void testLedgerEntryDirectory()
void testMissingLedgerEntryLedgerHash()
void testLedgerEntryPayChan()
diff --git a/STAmount_8cpp_source.html b/STAmount_8cpp_source.html index f5f7617d65..69070b79a5 100644 --- a/STAmount_8cpp_source.html +++ b/STAmount_8cpp_source.html @@ -1768,7 +1768,7 @@ $(function() {
STAmount divRoundStrict(STAmount const &num, STAmount const &den, Issue const &issue, bool roundUp)
Definition: STAmount.cpp:1613
@ towards_zero
Definition: Number.h:161
constexpr std::enable_if_t< std::is_same_v< typename Dest::unit_type, typename Src::unit_type > &&std::is_integral_v< typename Dest::value_type > &&std::is_integral_v< typename Src::value_type >, Dest > safe_cast(Src s) noexcept
Definition: FeeUnits.h:536
-
std::string getText() const
Definition: Issue.cpp:29
+
std::string getText() const
Definition: Issue.cpp:30
STAmount const & value() const noexcept
Definition: STAmount.h:440
T to_string(T... args)
static std::uint64_t muldiv(std::uint64_t multiplier, std::uint64_t multiplicand, std::uint64_t divisor)
Definition: STAmount.cpp:1108
diff --git a/STIssue_8cpp_source.html b/STIssue_8cpp_source.html index e4c76fbdbf..b400b2dade 100644 --- a/STIssue_8cpp_source.html +++ b/STIssue_8cpp_source.html @@ -197,17 +197,17 @@ $(function() {
Json::Value getJson(JsonOptions) const override
Definition: STIssue.cpp:63
static STBase * emplace(std::size_t n, void *buf, T &&val)
Definition: STBase.h:165
bool isEquivalent(const STBase &t) const override
Definition: STIssue.cpp:77
-
std::string getText() const
Definition: Issue.cpp:29
+
std::string getText() const
Definition: Issue.cpp:30
AccountID const & xrpAccount()
Compute AccountID from public key.
Definition: AccountID.cpp:168
bool isXRP(AccountID const &c)
Definition: AccountID.h:89
Definition: Serializer.h:311
-
Issue issueFromJson(Json::Value const &v)
Definition: Issue.cpp:77
+
Issue issueFromJson(Json::Value const &v)
Definition: Issue.cpp:78
static std::unique_ptr< STIssue > construct(SerialIter &, SField const &name)
Definition: STIssue.cpp:90
Definition: STIssue.h:31
Definition: Serializer.h:40
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
int addBitString(base_uint< Bits, Tag > const &v)
Definition: Serializer.h:98
-
Json::Value to_json(Issue const &is)
Definition: Issue.cpp:67
+
Json::Value to_json(Issue const &is)
Definition: Issue.cpp:68
Identifies fields.
Definition: SField.h:115
A type which can be exported to a well known binary format.
Definition: STBase.h:66
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition: Issue.h:105
diff --git a/STIssue_8h_source.html b/STIssue_8h_source.html index 6432bfb285..15ab93afc1 100644 --- a/STIssue_8h_source.html +++ b/STIssue_8h_source.html @@ -222,7 +222,7 @@ $(function() {
bool operator<(CanonicalTXSet::Key const &lhs, CanonicalTXSet::Key const &rhs)
bool isEquivalent(const STBase &t) const override
Definition: STIssue.cpp:77
Definition: Serializer.h:311
-
Issue issueFromJson(Json::Value const &v)
Definition: Issue.cpp:77
+
Issue issueFromJson(Json::Value const &v)
Definition: Issue.cpp:78
Issue const & value() const noexcept
Definition: STIssue.h:95
static std::unique_ptr< STIssue > construct(SerialIter &, SField const &name)
Definition: STIssue.cpp:90
Definition: STIssue.h:31
diff --git a/STParsedJSON_8cpp_source.html b/STParsedJSON_8cpp_source.html index 3a964c3042..54385382c5 100644 --- a/STParsedJSON_8cpp_source.html +++ b/STParsedJSON_8cpp_source.html @@ -1128,7 +1128,7 @@ $(function() {
STAmount amountFromJson(SField const &name, Json::Value const &v)
Definition: STAmount.cpp:916
-
Issue issueFromJson(Json::Value const &v)
Definition: Issue.cpp:77
+
Issue issueFromJson(Json::Value const &v)
Definition: Issue.cpp:78
@ STI_VECTOR256
Definition: SField.h:76
T from_chars(T... args)
constexpr std::enable_if_t< std::is_unsigned< U >::value &&std::is_signed< S >::value, U > to_unsigned(S value)
diff --git a/classripple_1_1Issue.html b/classripple_1_1Issue.html index 3ca25e5ce3..be1cf420e7 100644 --- a/classripple_1_1Issue.html +++ b/classripple_1_1Issue.html @@ -177,7 +177,7 @@ Public Attributes
-

Definition at line 29 of file Issue.cpp.

+

Definition at line 30 of file Issue.cpp.

diff --git a/classripple_1_1LedgerRPC__test.html b/classripple_1_1LedgerRPC__test.html index f5b3004744..2555b0d5c4 100644 --- a/classripple_1_1LedgerRPC__test.html +++ b/classripple_1_1LedgerRPC__test.html @@ -709,7 +709,7 @@ Private Member Functions

ledger RPC requests as a way to drive input options to lookupLedger.

The point of this test is coverage for lookupLedger, not so much the ledger RPC request.

-

Definition at line 1244 of file LedgerRPC_test.cpp.

+

Definition at line 1442 of file LedgerRPC_test.cpp.

@@ -736,7 +736,7 @@ Private Member Functions
-

Definition at line 1439 of file LedgerRPC_test.cpp.

+

Definition at line 1637 of file LedgerRPC_test.cpp.

@@ -763,7 +763,7 @@ Private Member Functions
-

Definition at line 1455 of file LedgerRPC_test.cpp.

+

Definition at line 1653 of file LedgerRPC_test.cpp.

@@ -790,7 +790,7 @@ Private Member Functions
-

Definition at line 1673 of file LedgerRPC_test.cpp.

+

Definition at line 1871 of file LedgerRPC_test.cpp.

@@ -817,7 +817,7 @@ Private Member Functions
-

Definition at line 1716 of file LedgerRPC_test.cpp.

+

Definition at line 1914 of file LedgerRPC_test.cpp.

diff --git a/namespaceripple.html b/namespaceripple.html index a858391d7e..2b40620060 100644 --- a/namespaceripple.html +++ b/namespaceripple.html @@ -31722,7 +31722,7 @@ template<class... Args>
-

Definition at line 52 of file Issue.cpp.

+

Definition at line 53 of file Issue.cpp.

@@ -31742,7 +31742,7 @@ template<class... Args>
-

Definition at line 58 of file Issue.cpp.

+

Definition at line 59 of file Issue.cpp.

@@ -31762,7 +31762,7 @@ template<class... Args>
-

Definition at line 67 of file Issue.cpp.

+

Definition at line 68 of file Issue.cpp.

@@ -31782,7 +31782,7 @@ template<class... Args>
-

Definition at line 77 of file Issue.cpp.

+

Definition at line 78 of file Issue.cpp.

@@ -31812,7 +31812,7 @@ template<class... Args>
-

Definition at line 127 of file Issue.cpp.

+

Definition at line 125 of file Issue.cpp.

@@ -46240,7 +46240,7 @@ template<typename L , typename R >
-

Definition at line 438 of file LedgerEntry.cpp.

+

Definition at line 466 of file LedgerEntry.cpp.

@@ -47287,7 +47287,7 @@ template<typename L , typename R >
-

Definition at line 40 of file LedgerEntry.cpp.

+

Definition at line 41 of file LedgerEntry.cpp.