Compare commits

...

87 Commits

Author SHA1 Message Date
Ed Hennis
e06f986437 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-12-05 21:12:47 -05:00
Bart
b986395ecc docs: Infer version of Conan dependency to export (#6112)
This change updates a script in the documentation to automatically infer the version of a patched Conan dependency from the conan.lock file.
2025-12-05 11:44:48 -05:00
Bart
020ea3f412 refactor: Update Conan dependencies: protobuf and grpc (#5589)
This PR updates protobuf and grpc to their latest versions. The latest protobuf version no longer requires patches, so we can use it directly from the official Conan Center Index, while the latest grpc still needed a patch, which was added to our own Conan Center Index fork in XRPLF/conan-center-index#8.
2025-12-04 10:34:37 -05:00
Ed Hennis
8a85440ffa Merge remote-tracking branch 'XRPLF/develop' into ximinez/fixed-ledger-entries
* XRPLF/develop:
  Implement Lending Protocol (unsupported) (5270)
2025-12-02 17:30:17 -05:00
Ed Hennis
0e436292ae Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-12-01 14:40:19 -05:00
Ed Hennis
e24da785ec Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-11-28 15:46:23 -05:00
Ed Hennis
12625e99c0 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-11-27 01:48:37 -05:00
Ed Hennis
10f9c18dd3 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-11-26 00:24:54 -05:00
Ed Hennis
13ab98fb4c Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-11-25 14:54:43 -05:00
Ed Hennis
fec2f60697 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-11-24 21:48:46 -05:00
Ed Hennis
528ede7864 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-11-24 21:29:56 -05:00
Ed Hennis
4dac87a1b8 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-11-21 12:47:33 -05:00
Ed Hennis
7c933e06a0 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-11-18 22:39:10 -05:00
Ed Hennis
d94722e4d0 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-11-15 03:08:21 -05:00
Ed Hennis
059092d773 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-11-13 12:18:19 -05:00
Ed Hennis
1cb0887436 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-11-12 13:59:49 -05:00
Ed Hennis
b9e289df55 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-11-10 19:52:46 -05:00
Ed Hennis
fff08cb2b1 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-11-10 15:35:00 -05:00
Ed Hennis
d3842b3908 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-11-08 22:49:30 -05:00
Ed Hennis
759bd4d199 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-11-06 23:50:26 -05:00
Ed Hennis
4c88dfc384 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-11-05 22:23:11 -05:00
Ed Hennis
f241378e6e Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-11-04 18:02:34 -05:00
Ed Hennis
c8ff090d8e Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-11-03 18:04:00 -05:00
Ed Hennis
945c362559 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-11-03 12:41:52 -05:00
Ed Hennis
9546c52013 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-10-31 13:51:19 -04:00
Ed Hennis
3a099aeb64 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-10-31 12:51:28 -04:00
Ed Hennis
8567bd0d12 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-10-29 14:23:15 -04:00
Ed Hennis
3cb1851537 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-10-29 13:42:25 -04:00
Ed Hennis
55feea308e Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-10-29 12:54:20 -04:00
Ed Hennis
a6692af17a Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-10-28 17:38:25 -04:00
Ed Hennis
1d058a5d78 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-10-26 19:12:36 -04:00
Ed Hennis
a70821adc5 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-10-23 13:24:29 -04:00
Ed Hennis
bfeb60d3f5 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-10-22 11:38:53 -04:00
Ed Hennis
c86bfa32f7 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-10-21 22:20:09 -04:00
Ed Hennis
0f44d619b6 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-10-17 18:21:41 -04:00
Ed Hennis
2add6a7917 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-10-16 13:12:12 -04:00
Ed Hennis
d21c4f3218 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-10-16 10:48:48 -04:00
Ed Hennis
265a504301 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-10-10 13:01:37 -04:00
Ed Hennis
b1e576d3d1 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-10-09 15:14:51 -04:00
Ed Hennis
d2d3039ce6 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-10-08 14:21:37 -04:00
Ed Hennis
16e85a7b79 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-10-02 11:03:12 -04:00
Ed Hennis
4ae1c01e13 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-10-01 18:11:01 -04:00
Ed Hennis
8807afc074 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-10-01 13:14:26 -04:00
Ed Hennis
a4e13e07d5 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-30 22:28:57 -04:00
Ed Hennis
6067d59336 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-29 18:34:47 -04:00
Ed Hennis
e14aecee66 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-29 13:32:16 -04:00
Ed Hennis
0e4c3e3427 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-26 19:26:10 -04:00
Ed Hennis
da5c563426 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-26 13:41:39 -04:00
Ed Hennis
b9f5d8b1c5 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-26 12:09:21 -04:00
Ed Hennis
5ea7b562a2 Review feedback from @mvadari: Document test lambdas 2025-09-25 14:23:10 -04:00
Ed Hennis
8450970b80 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-25 13:27:21 -04:00
Ed Hennis
14d4cff530 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-24 15:50:03 -04:00
Ed Hennis
88ac659d86 Move the lambda to the top so that the parse functions stay alphabetical 2025-09-24 12:54:47 -04:00
Ed Hennis
43fdbf27b9 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-20 15:44:43 -04:00
Ed Hennis
1e33f8e868 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-18 14:08:38 -04:00
Ed Hennis
a6e30857df Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-18 12:26:54 -04:00
Ed Hennis
563f24edb0 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-17 10:49:24 -04:00
Ed Hennis
a89f6d5da2 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-16 11:15:08 -04:00
Ed Hennis
5b2e91986a Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-15 11:13:49 -04:00
Ed Hennis
fbc5056817 Gate the new "index: special_case" on the current beta apiVersion 3 2025-09-12 14:02:38 -04:00
Ed Hennis
b7cafed040 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-11 10:33:34 -04:00
Ed Hennis
b6ebd34b30 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-10 19:40:02 -04:00
Ed Hennis
74c2765159 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-09 17:14:37 -04:00
Ed Hennis
62c7fdadba Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-08 11:42:06 -04:00
Ed Hennis
372c66e684 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-05 17:44:24 -04:00
Ed Hennis
a2fab5bcaf Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-04 20:25:13 -04:00
Ed Hennis
2e4f41571c Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-04 16:44:07 -04:00
Ed Hennis
8799a6dbfd Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-04 12:36:56 -04:00
Ed Hennis
e655087027 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-09-03 14:04:19 -04:00
Ed Hennis
46bd2a4090 Merge remote-tracking branch 'upstream/develop' into ximinez/fixed-ledger-entries
* upstream/develop:
  Refactor `ledger_entry` RPC source code and tests (5237)
2025-08-29 17:55:45 -04:00
Ed Hennis
f3b8a8aef3 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-08-29 10:43:07 -04:00
Ed Hennis
ee0c917e95 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-08-28 18:17:43 -04:00
Ed Hennis
375aedd340 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-08-27 11:15:17 -04:00
Ed Hennis
95397a7710 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-08-25 19:51:08 -04:00
Ed Hennis
7af8a52d27 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-08-22 20:34:53 -04:00
Ed Hennis
326a8093c9 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-08-22 19:31:27 -04:00
Ed Hennis
9f0e159205 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-08-22 19:08:59 -04:00
Ed Hennis
2fda101b44 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-08-21 11:39:13 -04:00
Ed Hennis
e6e1e4f9dd Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-08-19 16:05:38 -04:00
Ed Hennis
70591265e5 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-08-18 12:26:01 -04:00
Ed Hennis
ed1d477a45 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-08-08 18:23:40 -04:00
Ed Hennis
cd58f636d3 Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-08-06 21:03:20 -04:00
Ed Hennis
3152f2233f Merge branch 'develop' into ximinez/fixed-ledger-entries 2025-08-05 21:17:03 -04:00
Ed Hennis
0c147a895c Restrict which values are valid for fixed types.
- True or a ledger index for those that can't parameters
- Number, true, or a ledger index for "hashes".
2025-08-04 19:23:59 -04:00
Ed Hennis
cf80710ef1 Refactor a little bit to reduce future conflicts
- Specifically #5237
2025-08-04 17:38:52 -04:00
Ed Hennis
fc929ab984 Add support for "index":"fixed type" lookups in ledger_entry
- For example "index":"amendments" will return the amendments object as
  if the request was
  "index":"7DB0788C020F02780A673DC74757F23823FA3014C1866E72CC4CD8B226CD6EF4"
- Works for amendments, fee, nunl, and hashes (for the recent history
  list only).
- Always returns the valid computed index, even if the object is not
  found.
2025-08-04 17:23:45 -04:00
Ed Hennis
145a8817dc Add ledger_entry options for fee, amendments, NUNL, and hashes
- Request format for fee, amendments, and nunl is
  "fieldName":<any valid json>, including null. Because these types
  have no inputs to the index computation, any value
  works.
- Request format for hashes is "hashes":<uint value or any valid
  json>. If the value is numeric, and evaluates to a uint, return the
  hashes history page for that ledger sequence. (AKA "long" skip list.)
  Any other valid json value will return the "short" skip list.
2025-08-04 17:23:43 -04:00
7 changed files with 602 additions and 93 deletions

3
.gitignore vendored
View File

@@ -111,3 +111,6 @@ bld.rippled/
# Suggested in-tree build directory
/.build*/
# Locally patched Conan recipes
external/conan-center-index/

View File

@@ -141,21 +141,37 @@ Alternatively, you can pull the patched recipes into the repository and use them
locally:
```bash
# Extract the version number from the lockfile.
function extract_version {
version=$(cat conan.lock | sed -nE "s@.+${1}/(.+)#.+@\1@p" | head -n1)
echo ${version}
}
# Define which recipes to export.
recipes=(ed25519 grpc secp256k1 snappy soci)
# Selectively check out the recipes from our CCI fork.
cd external
mkdir -p conan-center-index
cd conan-center-index
git init
git remote add origin git@github.com:XRPLF/conan-center-index.git
git sparse-checkout init
git sparse-checkout set recipes/ed25519
git sparse-checkout add recipes/secp256k1
git sparse-checkout add recipes/snappy
git sparse-checkout add recipes/soci
for recipe in ${recipes[@]}; do
echo "Checking out ${recipe}..."
git sparse-checkout add recipes/${recipe}/all
done
git fetch origin master
git checkout master
conan export --version 2015.03 recipes/ed25519/all
conan export --version 0.7.0 recipes/secp256k1/all
conan export --version 1.1.10 recipes/snappy/all
conan export --version 4.0.3 recipes/soci/all
rm -rf .git
cd ../..
# Export the recipes into the local cache.
for recipe in ${recipes[@]}; do
version=$(extract_version ${recipe})
echo "Exporting ${recipe}/${version}..."
conan export --version $(extract_version ${recipe}) \
external/conan-center-index/recipes/${recipe}/all
done
```
In the case we switch to a newer version of a dependency that still requires a
@@ -385,19 +401,6 @@ tools.build:cxxflags=['-DBOOST_ASIO_DISABLE_CONCEPTS']
`--settings build_type=$BUILD_TYPE` or in the profile itself,
under the section `[settings]` with the key `build_type`.
If you are using a Microsoft Visual C++ compiler,
then you will need to ensure consistency between the `build_type` setting
and the `compiler.runtime` setting.
When `build_type` is `Release`, `compiler.runtime` should be `MT`.
When `build_type` is `Debug`, `compiler.runtime` should be `MTd`.
```
conan install .. --output-folder . --build missing --settings build_type=Release --settings compiler.runtime=MT
conan install .. --output-folder . --build missing --settings build_type=Debug --settings compiler.runtime=MTd
```
3. Configure CMake and pass the toolchain file generated by Conan, located at
`$OUTPUT_FOLDER/build/generators/conan_toolchain.cmake`.

View File

@@ -9,7 +9,7 @@
"secp256k1/0.7.0#9210e4c655d0a665400378a663960d17%1764261276.764",
"rocksdb/10.5.1#4a197eca381a3e5ae8adf8cffa5aacd0%1762797952.535",
"re2/20230301#ca3b241baec15bd31ea9187150e0b333%1764175362.029",
"protobuf/3.21.12#44ee56c0a6eea0c19aeeaca680370b88%1764175361.456",
"protobuf/6.32.1#f481fd276fc23a33b85a3ed1e898b693%1759134873.45",
"openssl/3.5.4#a1d5835cc6ed5c5b8f3cd5b9b5d24205%1760106486.594",
"nudb/2.0.9#fb8dfd1a5557f5e0528114c2da17721e%1763150366.909",
"lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504%1756234228.999",
@@ -17,19 +17,19 @@
"libbacktrace/cci.20210118#a7691bfccd8caaf66309df196790a5a1%1756230911.03",
"libarchive/3.8.1#ffee18995c706e02bf96e7a2f7042e0d%1764175360.142",
"jemalloc/5.3.0#e951da9cf599e956cebc117880d2d9f8%1729241615.244",
"grpc/1.50.1#02291451d1e17200293a409410d1c4e1%1756234248.958",
"ed25519/2015.03#17c1f1910e769f368025267a53c23c13%1764259445.491",
"grpc/1.72.0#f244a57bff01e708c55a1100b12e1589%1763158050.628",
"ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1764270189.893",
"doctest/2.4.12#eb9fb352fb2fdfc8abb17ec270945165%1762797941.757",
"date/3.0.4#862e11e80030356b53c2c38599ceb32b%1763584497.32",
"c-ares/1.34.5#5581c2b62a608b40bb85d965ab3ec7c8%1764175359.429",
"bzip2/1.0.8#c470882369c2d95c5c77e970c0c7e321%1764175359.429",
"boost/1.88.0#8852c0b72ce8271fb8ff7c53456d4983%1756223752.326",
"abseil/20230802.1#90ba607d4ee8fb5fb157c3db540671fc%1764175359.429"
"abseil/20250127.0#9e8e8cfc89a1324139fc0ee3bd4d8c8c%1753819045.301"
],
"build_requires": [
"zlib/1.3.1#b8bc2603263cf7eccbd6e17e66b0ed76%1756234269.497",
"strawberryperl/5.32.1.1#707032463aa0620fa17ec0d887f5fe41%1756234281.733",
"protobuf/3.21.12#44ee56c0a6eea0c19aeeaca680370b88%1764175361.456",
"protobuf/6.32.1#f481fd276fc23a33b85a3ed1e898b693%1759134873.45",
"nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1756234232.901",
"msys2/cci.latest#5b73b10144f73cc5bfe0572ed9be39e1%1751977009.857",
"m4/1.4.19#70dc8bbb33e981d119d2acc0175cf381%1763158052.846",
@@ -37,13 +37,13 @@
"cmake/3.31.10#313d16a1aa16bbdb2ca0792467214b76%1764175359.429",
"b2/5.3.3#107c15377719889654eb9a162a673975%1756234226.28",
"automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56",
"autoconf/2.71#51077f068e61700d65bb05541ea1e4b0%1731054366.86"
"autoconf/2.71#51077f068e61700d65bb05541ea1e4b0%1731054366.86",
"abseil/20250127.0#9e8e8cfc89a1324139fc0ee3bd4d8c8c%1753819045.301"
],
"python_requires": [],
"overrides": {
"protobuf/3.21.12": [
null,
"protobuf/3.21.12"
"protobuf/5.27.0": [
"protobuf/6.32.1"
],
"lz4/1.9.4": [
"lz4/1.10.0"

View File

@@ -20,12 +20,6 @@ compiler.libcxx={{detect_api.detect_libcxx(compiler, version, compiler_exe)}}
{% endif %}
[conf]
{% if compiler == "clang" and compiler_version >= 19 %}
grpc/1.50.1:tools.build:cxxflags+=['-Wno-missing-template-arg-list-after-template-kw']
{% endif %}
{% if compiler == "apple-clang" and compiler_version >= 17 %}
grpc/1.50.1:tools.build:cxxflags+=['-Wno-missing-template-arg-list-after-template-kw']
{% endif %}
{% if compiler == "gcc" and compiler_version < 13 %}
tools.build:cxxflags+=['-Wno-restrict']
{% endif %}

View File

@@ -29,7 +29,7 @@ class Xrpl(ConanFile):
requires = [
"ed25519/2015.03",
"grpc/1.50.1",
"grpc/1.72.0",
"libarchive/3.8.1",
"nudb/2.0.9",
"openssl/3.5.4",
@@ -43,7 +43,7 @@ class Xrpl(ConanFile):
]
tool_requires = [
"protobuf/3.21.12",
"protobuf/6.32.1",
]
default_options = {
@@ -61,6 +61,16 @@ class Xrpl(ConanFile):
"ed25519/*:shared": False,
"grpc/*:shared": False,
"grpc/*:secure": True,
"grpc/*:codegen": True,
"grpc/*:cpp_plugin": True,
"grpc/*:csharp_ext": False,
"grpc/*:csharp_plugin": False,
"grpc/*:node_plugin": False,
"grpc/*:objective_c_plugin": False,
"grpc/*:php_plugin": False,
"grpc/*:python_plugin": False,
"grpc/*:ruby_plugin": False,
"grpc/*:otel_plugin": False,
"libarchive/*:shared": False,
"libarchive/*:with_acl": False,
"libarchive/*:with_bzip2": False,
@@ -118,7 +128,7 @@ class Xrpl(ConanFile):
self.requires("boost/1.88.0", force=True, **transitive_headers_opt)
self.requires("date/3.0.4", **transitive_headers_opt)
self.requires("lz4/1.10.0", force=True)
self.requires("protobuf/3.21.12", force=True)
self.requires("protobuf/6.32.1", force=True)
self.requires("sqlite3/3.49.1", force=True)
if self.options.jemalloc:
self.requires("jemalloc/5.3.0")

View File

@@ -5,6 +5,8 @@
#include <test/jtx/multisign.h>
#include <test/jtx/xchain_bridge.h>
#include <xrpld/app/tx/apply.h>
#include <xrpl/beast/unit_test.h>
#include <xrpl/json/json_value.h>
#include <xrpl/protocol/AccountID.h>
@@ -2008,6 +2010,370 @@ class LedgerEntry_test : public beast::unit_test::suite
}
}
/// Test the ledger entry types that don't take parameters
void
testLedgerEntryFixed()
{
using namespace test::jtx;
Account const alice{"alice"};
Account const bob{"bob"};
Env env{*this, envconfig([](auto cfg) {
cfg->START_UP = Config::FRESH;
return cfg;
})};
env.close();
/** Verifies that the RPC result has the expected data
*
* @param good: Indicates that the request should have succeeded
* and returned a ledger object of `expectedType` type.
* @param jv: The RPC result Json value
* @param expectedType: The type that the ledger object should
* have if "good".
* @param expectedError: Optional. The expected error if not
* good. Defaults to "entryNotFound".
*/
auto checkResult =
[&](bool good,
Json::Value const& jv,
Json::StaticString const& expectedType,
std::optional<std::string> const& expectedError = {}) {
if (good)
{
BEAST_EXPECTS(
jv.isObject() && jv.isMember(jss::result) &&
!jv[jss::result].isMember(jss::error) &&
jv[jss::result].isMember(jss::node) &&
jv[jss::result][jss::node].isMember(
sfLedgerEntryType.jsonName) &&
jv[jss::result][jss::node]
[sfLedgerEntryType.jsonName] == expectedType,
to_string(jv));
}
else
{
BEAST_EXPECTS(
jv.isObject() && jv.isMember(jss::result) &&
jv[jss::result].isMember(jss::error) &&
!jv[jss::result].isMember(jss::node) &&
jv[jss::result][jss::error] ==
expectedError.value_or("entryNotFound"),
to_string(jv));
}
};
/** Runs a series of tests for a given fixed-position ledger
* entry.
*
* @param field: The Json request field to use.
* @param expectedType: The type that the ledger object should
* have if "good".
* @param expectedKey: The keylet of the fixed object.
* @param good: Indicates whether the object is expected to
* exist.
*/
auto test = [&](Json::StaticString const& field,
Json::StaticString const& expectedType,
Keylet const& expectedKey,
bool good) {
testcase << "ledger_entry " << expectedType.c_str()
<< (good ? "" : " not") << " found";
auto const hexKey = strHex(expectedKey.key);
// Test bad values
// "field":null
Json::Value params;
params[jss::ledger_index] = jss::validated;
params[field] = Json::nullValue;
auto jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, expectedType, "malformedRequest");
BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
// "field":"string"
params.clear();
params[jss::ledger_index] = jss::validated;
params[field] = "arbitrary string";
jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, expectedType, "malformedRequest");
BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
// "field":false
params.clear();
params[jss::ledger_index] = jss::validated;
params[field] = false;
jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, expectedType, "invalidParams");
BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
{
// "field":[incorrect index hash]
auto const badKey = strHex(expectedKey.key + uint256{1});
params.clear();
params[jss::ledger_index] = jss::validated;
params[field] = badKey;
jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, expectedType, "entryNotFound");
BEAST_EXPECTS(
jv[jss::result][jss::index] == badKey, to_string(jv));
}
// "index":"field" using API 2
params.clear();
params[jss::ledger_index] = jss::validated;
params[jss::index] = field;
params[jss::api_version] = 2;
jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, expectedType, "malformedRequest");
BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
// Test good values
// Use the "field":true notation
params.clear();
params[jss::ledger_index] = jss::validated;
params[field] = true;
jv = env.rpc("json", "ledger_entry", to_string(params));
// Index will always be returned for valid parameters.
std::string const pdIdx = jv[jss::result][jss::index].asString();
BEAST_EXPECTS(hexKey == pdIdx, to_string(jv));
checkResult(good, jv, expectedType);
// "field":"[index hash]"
params.clear();
params[jss::ledger_index] = jss::validated;
params[field] = hexKey;
jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(good, jv, expectedType);
BEAST_EXPECT(jv[jss::result][jss::index].asString() == hexKey);
// Use the "index":"field" notation with API 3
params.clear();
params[jss::ledger_index] = jss::validated;
params[jss::index] = field;
params[jss::api_version] = 3;
jv = env.rpc("json", "ledger_entry", to_string(params));
// Index is correct either way
BEAST_EXPECT(jv[jss::result][jss::index].asString() == hexKey);
checkResult(good, jv, expectedType);
// Use the "index":"[index hash]" notation
params.clear();
params[jss::ledger_index] = jss::validated;
params[jss::index] = pdIdx;
jv = env.rpc("json", "ledger_entry", to_string(params));
// Index is correct either way
BEAST_EXPECT(jv[jss::result][jss::index].asString() == hexKey);
checkResult(good, jv, expectedType);
};
test(jss::amendments, jss::Amendments, keylet::amendments(), true);
test(jss::fee, jss::FeeSettings, keylet::fees(), true);
// There won't be an nunl
test(jss::nunl, jss::NegativeUNL, keylet::negativeUNL(), false);
// Can only get the short skip list this way
test(jss::hashes, jss::LedgerHashes, keylet::skip(), true);
}
void
testLedgerEntryHashes()
{
using namespace test::jtx;
Account const alice{"alice"};
Account const bob{"bob"};
Env env{*this, envconfig([](auto cfg) {
cfg->START_UP = Config::FRESH;
return cfg;
})};
env.close();
/** Verifies that the RPC result has the expected data
*
* @param good: Indicates that the request should have succeeded
* and returned a ledger object of `expectedType` type.
* @param jv: The RPC result Json value
* @param expectedCount: The number of Hashes expected in the
* object if "good".
* @param expectedError: Optional. The expected error if not
* good. Defaults to "entryNotFound".
*/
auto checkResult =
[&](bool good,
Json::Value const& jv,
int expectedCount,
std::optional<std::string> const& expectedError = {}) {
if (good)
{
BEAST_EXPECTS(
jv.isObject() && jv.isMember(jss::result) &&
!jv[jss::result].isMember(jss::error) &&
jv[jss::result].isMember(jss::node) &&
jv[jss::result][jss::node].isMember(
sfLedgerEntryType.jsonName) &&
jv[jss::result][jss::node]
[sfLedgerEntryType.jsonName] == jss::LedgerHashes,
to_string(jv));
BEAST_EXPECTS(
jv[jss::result].isMember(jss::node) &&
jv[jss::result][jss::node].isMember("Hashes") &&
jv[jss::result][jss::node]["Hashes"].size() ==
expectedCount,
to_string(jv[jss::result][jss::node]["Hashes"].size()));
}
else
{
BEAST_EXPECTS(
jv.isObject() && jv.isMember(jss::result) &&
jv[jss::result].isMember(jss::error) &&
!jv[jss::result].isMember(jss::node) &&
jv[jss::result][jss::error] ==
expectedError.value_or("entryNotFound"),
to_string(jv));
}
};
/** Runs a series of tests for a given ledger index.
*
* @param ledger: The ledger index value of the "hashes" request
* parameter. May not necessarily be a number.
* @param expectedKey: The expected keylet of the object.
* @param good: Indicates whether the object is expected to
* exist.
* @param expectedCount: The number of Hashes expected in the
* object if "good".
*/
auto test = [&](Json::Value ledger,
Keylet const& expectedKey,
bool good,
int expectedCount = 0) {
testcase << "ledger_entry LedgerHashes: seq: "
<< env.current()->info().seq
<< " \"hashes\":" << to_string(ledger)
<< (good ? "" : " not") << " found";
auto const hexKey = strHex(expectedKey.key);
// Test bad values
// "hashes":null
Json::Value params;
params[jss::ledger_index] = jss::validated;
params[jss::hashes] = Json::nullValue;
auto jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, 0, "malformedRequest");
BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
// "hashes":"non-uint string"
params.clear();
params[jss::ledger_index] = jss::validated;
params[jss::hashes] = "arbitrary string";
jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, 0, "malformedRequest");
BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
// "hashes":"uint string" is invalid, too
params.clear();
params[jss::ledger_index] = jss::validated;
params[jss::hashes] = "10";
jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, 0, "malformedRequest");
BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
// "hashes":false
params.clear();
params[jss::ledger_index] = jss::validated;
params[jss::hashes] = false;
jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, 0, "invalidParams");
BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
// "hashes":-1
params.clear();
params[jss::ledger_index] = jss::validated;
params[jss::hashes] = -1;
jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, 0, "internal");
BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
// "hashes":[incorrect index hash]
{
auto const badKey = strHex(expectedKey.key + uint256{1});
params.clear();
params[jss::ledger_index] = jss::validated;
params[jss::hashes] = badKey;
jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, 0, "entryNotFound");
BEAST_EXPECT(jv[jss::result][jss::index] == badKey);
}
// Test good values
// Use the "hashes":ledger notation
params.clear();
params[jss::ledger_index] = jss::validated;
params[jss::hashes] = ledger;
jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(good, jv, expectedCount);
// Index will always be returned for valid parameters.
std::string const pdIdx = jv[jss::result][jss::index].asString();
BEAST_EXPECTS(hexKey == pdIdx, strHex(pdIdx));
// "hashes":"[index hash]"
params.clear();
params[jss::ledger_index] = jss::validated;
params[jss::hashes] = hexKey;
jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(good, jv, expectedCount);
// Index is correct either way
BEAST_EXPECTS(
hexKey == jv[jss::result][jss::index].asString(),
strHex(jv[jss::result][jss::index].asString()));
// Use the "index":"[index hash]" notation
params.clear();
params[jss::ledger_index] = jss::validated;
params[jss::index] = hexKey;
jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(good, jv, expectedCount);
// Index is correct either way
BEAST_EXPECTS(
hexKey == jv[jss::result][jss::index].asString(),
strHex(jv[jss::result][jss::index].asString()));
};
// short skip list
test(true, keylet::skip(), true, 2);
// long skip list at index 0
test(1, keylet::skip(1), false);
// long skip list at index 1
test(1 << 17, keylet::skip(1 << 17), false);
// Close more ledgers, but stop short of the flag ledger
for (auto i = env.current()->seq(); i <= 250; ++i)
env.close();
// short skip list
test(true, keylet::skip(), true, 249);
// long skip list at index 0
test(1, keylet::skip(1), false);
// long skip list at index 1
test(1 << 17, keylet::skip(1 << 17), false);
// Close a flag ledger so the first "long" skip list is created
for (auto i = env.current()->seq(); i <= 260; ++i)
env.close();
// short skip list
test(true, keylet::skip(), true, 256);
// long skip list at index 0
test(1, keylet::skip(1), true, 1);
// long skip list at index 1
test(1 << 17, keylet::skip(1 << 17), false);
}
void
testLedgerEntryCLI()
{
@@ -2057,6 +2423,8 @@ public:
testOracleLedgerEntry();
testLedgerEntryMPT();
testLedgerEntryPermissionedDomain();
testLedgerEntryFixed();
testLedgerEntryHashes();
testLedgerEntryCLI();
}
};

View File

@@ -18,6 +18,32 @@
namespace ripple {
using FunctionType = std::function<Expected<uint256, Json::Value>(
Json::Value const&,
Json::StaticString const,
unsigned apiVersion)>;
static Expected<uint256, Json::Value>
parseFixed(
Keylet const& keylet,
Json::Value const& params,
Json::StaticString const& fieldName,
unsigned apiVersion);
// Helper function to return FunctionType for objects that have a fixed
// location. That is, they don't take parameters to compute the index.
// e.g. amendments, fees, negative UNL, etc.
static FunctionType
fixed(Keylet const& keylet)
{
return [&keylet](
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion) -> Expected<uint256, Json::Value> {
return parseFixed(keylet, params, fieldName, apiVersion);
};
}
static Expected<uint256, Json::Value>
parseObjectID(
Json::Value const& params,
@@ -33,13 +59,33 @@ parseObjectID(
}
static Expected<uint256, Json::Value>
parseIndex(Json::Value const& params, Json::StaticString const fieldName)
parseIndex(
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion)
{
if (apiVersion > 2u && params.isString())
{
std::string const index = params.asString();
if (index == jss::amendments.c_str())
return keylet::amendments().key;
if (index == jss::fee.c_str())
return keylet::fees().key;
if (index == jss::nunl)
return keylet::negativeUNL().key;
if (index == jss::hashes)
// Note this only finds the "short" skip list. Use "hashes":index to
// get the long list.
return keylet::skip().key;
}
return parseObjectID(params, fieldName, "hex string");
}
static Expected<uint256, Json::Value>
parseAccountRoot(Json::Value const& params, Json::StaticString const fieldName)
parseAccountRoot(
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion)
{
if (auto const account = LedgerEntryHelpers::parse<AccountID>(params))
{
@@ -50,14 +96,13 @@ parseAccountRoot(Json::Value const& params, Json::StaticString const fieldName)
"malformedAddress", fieldName, "AccountID");
}
static Expected<uint256, Json::Value>
parseAmendments(Json::Value const& params, Json::StaticString const fieldName)
{
return parseObjectID(params, fieldName, "hex string");
}
auto const parseAmendments = fixed(keylet::amendments());
static Expected<uint256, Json::Value>
parseAMM(Json::Value const& params, Json::StaticString const fieldName)
parseAMM(
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion)
{
if (!params.isObject())
{
@@ -84,7 +129,10 @@ parseAMM(Json::Value const& params, Json::StaticString const fieldName)
}
static Expected<uint256, Json::Value>
parseBridge(Json::Value const& params, Json::StaticString const fieldName)
parseBridge(
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion)
{
if (!params.isMember(jss::bridge))
{
@@ -115,13 +163,19 @@ parseBridge(Json::Value const& params, Json::StaticString const fieldName)
}
static Expected<uint256, Json::Value>
parseCheck(Json::Value const& params, Json::StaticString const fieldName)
parseCheck(
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion)
{
return parseObjectID(params, fieldName, "hex string");
}
static Expected<uint256, Json::Value>
parseCredential(Json::Value const& cred, Json::StaticString const fieldName)
parseCredential(
Json::Value const& cred,
Json::StaticString const fieldName,
unsigned apiVersion)
{
if (!cred.isObject())
{
@@ -152,7 +206,10 @@ parseCredential(Json::Value const& cred, Json::StaticString const fieldName)
}
static Expected<uint256, Json::Value>
parseDelegate(Json::Value const& params, Json::StaticString const fieldName)
parseDelegate(
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion)
{
if (!params.isObject())
{
@@ -243,7 +300,10 @@ parseAuthorizeCredentials(Json::Value const& jv)
}
static Expected<uint256, Json::Value>
parseDepositPreauth(Json::Value const& dp, Json::StaticString const fieldName)
parseDepositPreauth(
Json::Value const& dp,
Json::StaticString const fieldName,
unsigned apiVersion)
{
if (!dp.isObject())
{
@@ -296,7 +356,10 @@ parseDepositPreauth(Json::Value const& dp, Json::StaticString const fieldName)
}
static Expected<uint256, Json::Value>
parseDID(Json::Value const& params, Json::StaticString const fieldName)
parseDID(
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion)
{
auto const account = LedgerEntryHelpers::parse<AccountID>(params);
if (!account)
@@ -311,7 +374,8 @@ parseDID(Json::Value const& params, Json::StaticString const fieldName)
static Expected<uint256, Json::Value>
parseDirectoryNode(
Json::Value const& params,
Json::StaticString const fieldName)
Json::StaticString const fieldName,
unsigned apiVersion)
{
if (!params.isObject())
{
@@ -364,7 +428,10 @@ parseDirectoryNode(
}
static Expected<uint256, Json::Value>
parseEscrow(Json::Value const& params, Json::StaticString const fieldName)
parseEscrow(
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion)
{
if (!params.isObject())
{
@@ -383,20 +450,53 @@ parseEscrow(Json::Value const& params, Json::StaticString const fieldName)
return keylet::escrow(*id, *seq).key;
}
auto const parseFeeSettings = fixed(keylet::fees());
static Expected<uint256, Json::Value>
parseFeeSettings(Json::Value const& params, Json::StaticString const fieldName)
parseFixed(
Keylet const& keylet,
Json::Value const& params,
Json::StaticString const& fieldName,
unsigned apiVersion)
{
return parseObjectID(params, fieldName, "hex string");
if (!params.isBool())
{
return parseObjectID(params, fieldName, "hex string");
}
if (!params.asBool())
{
return LedgerEntryHelpers::invalidFieldError(
"invalidParams", fieldName, "true");
}
return keylet.key;
}
static Expected<uint256, Json::Value>
parseLedgerHashes(Json::Value const& params, Json::StaticString const fieldName)
parseLedgerHashes(
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion)
{
return parseObjectID(params, fieldName, "hex string");
if (params.isUInt() || params.isInt())
{
// If the index doesn't parse as a UInt, throw
auto const index = params.asUInt();
// Return the "long" skip list for the given ledger index.
auto const keylet = keylet::skip(index);
return keylet.key;
}
// Return the key in `params` or the "short" skip list, which contains
// hashes since the last flag ledger.
return parseFixed(keylet::skip(), params, fieldName, apiVersion);
}
static Expected<uint256, Json::Value>
parseLoanBroker(Json::Value const& params, Json::StaticString const fieldName)
parseLoanBroker(
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion)
{
if (!params.isObject())
{
@@ -416,7 +516,10 @@ parseLoanBroker(Json::Value const& params, Json::StaticString const fieldName)
}
static Expected<uint256, Json::Value>
parseLoan(Json::Value const& params, Json::StaticString const fieldName)
parseLoan(
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion)
{
if (!params.isObject())
{
@@ -436,7 +539,10 @@ parseLoan(Json::Value const& params, Json::StaticString const fieldName)
}
static Expected<uint256, Json::Value>
parseMPToken(Json::Value const& params, Json::StaticString const fieldName)
parseMPToken(
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion)
{
if (!params.isObject())
{
@@ -459,7 +565,8 @@ parseMPToken(Json::Value const& params, Json::StaticString const fieldName)
static Expected<uint256, Json::Value>
parseMPTokenIssuance(
Json::Value const& params,
Json::StaticString const fieldName)
Json::StaticString const fieldName,
unsigned apiVersion)
{
auto const mptIssuanceID = LedgerEntryHelpers::parse<uint192>(params);
if (!mptIssuanceID)
@@ -470,25 +577,30 @@ parseMPTokenIssuance(
}
static Expected<uint256, Json::Value>
parseNFTokenOffer(Json::Value const& params, Json::StaticString const fieldName)
parseNFTokenOffer(
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion)
{
return parseObjectID(params, fieldName, "hex string");
}
static Expected<uint256, Json::Value>
parseNFTokenPage(Json::Value const& params, Json::StaticString const fieldName)
parseNFTokenPage(
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion)
{
return parseObjectID(params, fieldName, "hex string");
}
static Expected<uint256, Json::Value>
parseNegativeUNL(Json::Value const& params, Json::StaticString const fieldName)
{
return parseObjectID(params, fieldName, "hex string");
}
auto const parseNegativeUNL = fixed(keylet::negativeUNL());
static Expected<uint256, Json::Value>
parseOffer(Json::Value const& params, Json::StaticString const fieldName)
parseOffer(
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion)
{
if (!params.isObject())
{
@@ -509,7 +621,10 @@ parseOffer(Json::Value const& params, Json::StaticString const fieldName)
}
static Expected<uint256, Json::Value>
parseOracle(Json::Value const& params, Json::StaticString const fieldName)
parseOracle(
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion)
{
if (!params.isObject())
{
@@ -530,7 +645,10 @@ parseOracle(Json::Value const& params, Json::StaticString const fieldName)
}
static Expected<uint256, Json::Value>
parsePayChannel(Json::Value const& params, Json::StaticString const fieldName)
parsePayChannel(
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion)
{
return parseObjectID(params, fieldName, "hex string");
}
@@ -538,7 +656,8 @@ parsePayChannel(Json::Value const& params, Json::StaticString const fieldName)
static Expected<uint256, Json::Value>
parsePermissionedDomain(
Json::Value const& pd,
Json::StaticString const fieldName)
Json::StaticString const fieldName,
unsigned apiVersion)
{
if (pd.isString())
{
@@ -567,7 +686,8 @@ parsePermissionedDomain(
static Expected<uint256, Json::Value>
parseRippleState(
Json::Value const& jvRippleState,
Json::StaticString const fieldName)
Json::StaticString const fieldName,
unsigned apiVersion)
{
Currency uCurrency;
@@ -617,13 +737,19 @@ parseRippleState(
}
static Expected<uint256, Json::Value>
parseSignerList(Json::Value const& params, Json::StaticString const fieldName)
parseSignerList(
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion)
{
return parseObjectID(params, fieldName, "hex string");
}
static Expected<uint256, Json::Value>
parseTicket(Json::Value const& params, Json::StaticString const fieldName)
parseTicket(
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion)
{
if (!params.isObject())
{
@@ -644,7 +770,10 @@ parseTicket(Json::Value const& params, Json::StaticString const fieldName)
}
static Expected<uint256, Json::Value>
parseVault(Json::Value const& params, Json::StaticString const fieldName)
parseVault(
Json::Value const& params,
Json::StaticString const fieldName,
unsigned apiVersion)
{
if (!params.isObject())
{
@@ -667,7 +796,8 @@ parseVault(Json::Value const& params, Json::StaticString const fieldName)
static Expected<uint256, Json::Value>
parseXChainOwnedClaimID(
Json::Value const& claim_id,
Json::StaticString const fieldName)
Json::StaticString const fieldName,
unsigned apiVersion)
{
if (!claim_id.isObject())
{
@@ -692,7 +822,8 @@ parseXChainOwnedClaimID(
static Expected<uint256, Json::Value>
parseXChainOwnedCreateAccountClaimID(
Json::Value const& claim_id,
Json::StaticString const fieldName)
Json::StaticString const fieldName,
unsigned apiVersion)
{
if (!claim_id.isObject())
{
@@ -716,10 +847,6 @@ parseXChainOwnedCreateAccountClaimID(
return keylet.key;
}
using FunctionType = Expected<uint256, Json::Value> (*)(
Json::Value const&,
Json::StaticString const);
struct LedgerEntry
{
Json::StaticString fieldName;
@@ -752,7 +879,7 @@ doLedgerEntry(RPC::JsonContext& context)
{jss::ripple_state, parseRippleState, ltRIPPLE_STATE},
});
auto hasMoreThanOneMember = [&]() {
auto const hasMoreThanOneMember = [&]() {
int count = 0;
for (auto const& ledgerEntry : ledgerEntryParsers)
@@ -796,8 +923,8 @@ doLedgerEntry(RPC::JsonContext& context)
Json::Value const& params = ledgerEntry.fieldName == jss::bridge
? context.params
: context.params[ledgerEntry.fieldName];
auto const result =
ledgerEntry.parseFunction(params, ledgerEntry.fieldName);
auto const result = ledgerEntry.parseFunction(
params, ledgerEntry.fieldName, context.apiVersion);
if (!result)
return result.error();
@@ -828,9 +955,13 @@ doLedgerEntry(RPC::JsonContext& context)
throw;
}
// Return the computed index regardless of whether the node exists.
jvResult[jss::index] = to_string(uNodeIndex);
if (uNodeIndex.isZero())
{
return RPC::make_error(rpcENTRY_NOT_FOUND);
RPC::inject_error(rpcENTRY_NOT_FOUND, jvResult);
return jvResult;
}
auto const sleNode = lpLedger->read(keylet::unchecked(uNodeIndex));
@@ -842,12 +973,14 @@ doLedgerEntry(RPC::JsonContext& context)
if (!sleNode)
{
// Not found.
return RPC::make_error(rpcENTRY_NOT_FOUND);
RPC::inject_error(rpcENTRY_NOT_FOUND, jvResult);
return jvResult;
}
if ((expectedType != ltANY) && (expectedType != sleNode->getType()))
{
return RPC::make_error(rpcUNEXPECTED_LEDGER_TYPE);
RPC::inject_error(rpcUNEXPECTED_LEDGER_TYPE, jvResult);
return jvResult;
}
if (bNodeBinary)
@@ -857,12 +990,10 @@ doLedgerEntry(RPC::JsonContext& context)
sleNode->add(s);
jvResult[jss::node_binary] = strHex(s.peekData());
jvResult[jss::index] = to_string(uNodeIndex);
}
else
{
jvResult[jss::node] = sleNode->getJson(JsonOptions::none);
jvResult[jss::index] = to_string(uNodeIndex);
}
return jvResult;