mirror of
https://github.com/XRPLF/rippled.git
synced 2026-10-28 06:27:12 +00:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6531dd532 | ||
|
|
ed9f859059 | ||
|
|
efad8c63b9 | ||
|
|
f4473147b7 | ||
|
|
fabd2070bd | ||
|
|
1f2a0d7991 | ||
|
|
73611f8b20 | ||
|
|
297f255988 | ||
|
|
89c01342c5 | ||
|
|
8f49ff629d | ||
|
|
1f46f75318 |
No files matched your search
@@ -51,8 +51,6 @@ IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: "^<(test)/"
|
||||
Priority: 1
|
||||
- Regex: "^<(tests)/"
|
||||
Priority: 1
|
||||
- Regex: "^<(xrpld)/"
|
||||
Priority: 2
|
||||
- Regex: "^<(xrpl)/"
|
||||
|
||||
+5
-1
@@ -140,5 +140,9 @@ CheckOptions:
|
||||
readability-identifier-naming.GlobalFunctionIgnoredRegexp: "^(to_string|hash_append|tuple_hash)$"
|
||||
|
||||
HeaderFilterRegex: '^.*/(tests?|xrpl|xrpld)/.*\.(h|hpp|ipp)$'
|
||||
ExcludeHeaderFilterRegex: '^.*/protocol_autogen/.*\.(h|hpp)$|^.*\.pb\.h$'
|
||||
# Skip headers reached via add_module's symlinks (<build-dir>/modules/xrpl.lib*/...).
|
||||
# verify_headers already checks each one under its real path,
|
||||
# so reporting it twice would also apply its fixes twice.
|
||||
# .ipp files are kept: they are only ever reached via the symlink.
|
||||
ExcludeHeaderFilterRegex: '^.*/protocol_autogen/.*\.(h|hpp)$|^.*\.pb\.h$|^.*/modules/xrpl\.lib[^/]+/.*\.(h|hpp)$'
|
||||
WarningsAsErrors: "*"
|
||||
@@ -14,9 +14,6 @@ endfunction()
|
||||
function(xrpl_add_benchmark name)
|
||||
endfunction()
|
||||
|
||||
function(xrpl_add_test_dir name)
|
||||
endfunction()
|
||||
|
||||
macro(exclude_from_default target_)
|
||||
endmacro()
|
||||
|
||||
|
||||
@@ -175,8 +175,10 @@ test.server > xrpl.basics
|
||||
test.server > xrpl.config
|
||||
test.server > xrpld.app
|
||||
test.server > xrpld.core
|
||||
test.server > xrpld.rpc
|
||||
test.server > xrpl.json
|
||||
test.server > xrpl.protocol
|
||||
test.server > xrpl.resource
|
||||
test.server > xrpl.server
|
||||
test.unit_test > xrpl.basics
|
||||
test.unit_test > xrpl.protocol
|
||||
|
||||
@@ -22,6 +22,23 @@ API version 2 is available in `xrpld` version 2.0.0 and later. See [API-VERSION-
|
||||
|
||||
This version is supported by all `xrpld` versions. For WebSocket and HTTP JSON-RPC requests, it is currently the default API version used when no `api_version` is specified.
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Breaking changes
|
||||
|
||||
- A JSON string holding a NUL character, written as `\u0000` or as a raw byte, now makes the request unparsable, on every transport and at every API version, and is answered as any other body that does not parse. The server stored a string only through its first NUL, so `"ripplerpc": "3.0\u0000junk"` was read as `"3.0"` and any other field was cut short the same way. The two configuration sections read by the same parser, `[rpc_startup]` and `[validator_token]`, refuse it too.
|
||||
- The `ripplerpc` request field, which selects the shape of the JSON-RPC reply envelope, is now validated, and a value that is not exactly `"1.0"`, `"2.0"` or `"3.0"` is rejected. This reaches the JSON-RPC transport at every API version. It does not reach a WebSocket session, which reads the field only to echo it back. A request sending `"2"`, `" 2.0"`, `"2.00"`, `"02.0"`, `"2.0.0"`, `"10.0"` or any other text, such as `"abc"` or `"x2"`, gets a working reply today. After this ships, such a request sent alone gets HTTP 400 with `ripplerpc is not a supported version`, charged as a malformed request, and such an entry of a `"method": "batch"` body gets that error in its own reply while the batch answers 200. A client that spells the version loosely must therefore be corrected to one of the three exact values, or omit the field. Previously the value was compared as a string, which both accepted values that name no version and ordered multi-digit versions incorrectly: `"abc"` and `"x2"` sorted above `"3.0"` and so selected version 3, and `"10.0"` sorted below `"2.0"` and so selected version 1. Requests that send one of the three supported values, or omit the field, are unaffected.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- Every credential-bearing field is masked wherever a request or a reply is echoed, logged or printed: `admin_password`, `admin_user`, `master_key`, `master_seed`, `master_seed_hex`, `passphrase`, `password`, `secret`, `seed`, `seed_hex`, `url_password`, `url_username`, `username`, `validation_key`, `validation_private_key` and `validation_seed`. The one list applies to a request echoed back in an error reply and to every request and reply written to the log. Nesting no longer matters, so a credential inside `params` is masked too. Six of the sixteen names, `master_key`, `master_seed`, `master_seed_hex`, `validation_key`, `validation_private_key` and `validation_seed`, occur only in a reply, which is how `wallet_propose` and `validation_create` used to write a live private key to the log. The `id`, `jsonrpc`, `ripplerpc` and `api_version` members a legacy reply echoes from the request are masked the same way. The command line client's trace of a reply's header covers the header only, not the body bytes read with it. A request or reply written to the log is truncated at 10,000 characters. An `[rpc_startup]` line that does not parse is reported by its position in the section alone, never by its text or by the parser's message, and no command runs for it.
|
||||
- The command line client no longer prints a credential the operator did not type. A failing command echoes the request it built under `request_sent`, which carries the `admin_password` the client copies out of `[port_rpc]` in the config, so `./xrpld account_info rBogus` printed that password to stdout and into any captured output. `request_sent` is now masked. The `rpc` member beside it, which echoes the arguments as they were typed, is unchanged. The command line client also no longer writes an unparsed `json` or `ripple_path_find` argument to its trace log before parsing it, where a `secret` inside that argument could not be masked; it logs the parsed request instead, masked. The reply it receives is logged the same way, parsed and masked, where the raw body was written before, a `validation_create` answer included.
|
||||
- A WebSocket frame that does not parse, or exceeds the request size limit, is answered `{"type": "error", "error": "jsonInvalid", "size": <bytes>}`. The frame's body is reported by size rather than echoed back in a `value` member, since a body that does not parse has no fields to mask. A client that read `value` gets `size` instead.
|
||||
- Four error codes that named no HTTP status of their own, and so answered 200 on a reply reporting an error, now name one: `actMalformed`, `alreadyMultisig` and `alreadySingleSig` answer 400, and `actNotFound` answers 404. **No shipped envelope reports these four.** A request sending `ripplerpc: "3.0"` still receives 200 for all four, as it always has, so `account_info` on a malformed account or one the ledger does not hold answers 200 exactly as before.
|
||||
- `submit`, `simulate`, `transaction_entry`, `ledger_entry` and `ledger_accept`: Errors from these methods now include `error_code` and `error_message` alongside the `error` token, as every other method already did. Each error now answers the status its code names: 400 for a malformed request, 404 for `transactionNotFound`, 500 for an internal failure, and 501 for `notYetImplemented` and `notStandAlone`. That status change reaches only a request sending `ripplerpc: "3.0"`, which is the envelope that derives the status from the error. With `ripplerpc` `"1.0"` the status stays 200 and the two new members appear beside `error`; with `"2.0"` the status stays 200, `error_code` appears, and the `code` and `message` members carry the code and the message rather than null, since that envelope copies them from `error_code` and `error_message` and drops `error_message`.
|
||||
- A reply reporting HTTP 402 or 502 now carries a status line. Those two statuses named no case in the switch that writes one, so such a reply began with a header instead and did not parse as an HTTP response at all. Both are reachable at any API version with `ripplerpc: "3.0"`, which derives the status from the error code: 402 through `highFee` from `sign` or `submit` with a low `fee_mult_max`, and 502 through `dbDeserialization` from `tx`. The eleven statuses that already named a case report the same phrase they always have.
|
||||
- An error reply to a request sending `ripplerpc: "2.0"` or `"3.0"` no longer carries a stray `"error_message": null` beside the error it reports. The member appeared only when the `Server` log partition was set to debug or lower, because the log statement read `error_message` after the reply had renamed it to `message`, and reading it put it back as null. So the reply a client received depended on the server's log level, and the log line itself printed an empty message. Both are fixed.
|
||||
|
||||
## XRP Ledger server version 3.5.0
|
||||
|
||||
Version 3.5.0 is not yet released.
|
||||
|
||||
+4
-3
@@ -365,14 +365,15 @@ With this set, the hook will run as part of `git commit` alongside the other pre
|
||||
Then run clang-tidy on your local changes:
|
||||
|
||||
```
|
||||
run-clang-tidy -p build -allow-no-checks src tests
|
||||
run-clang-tidy -p build -allow-no-checks include src tests
|
||||
```
|
||||
|
||||
This will check all source files in the `src`, `include` and `tests` directories using the compile commands from your `build` directory.
|
||||
This will check all source files in the `include`, `src` and `tests` directories using the compile commands from your `build` directory.
|
||||
Headers are checked on their own, which requires the `verify_headers` CMake option (ON by default).
|
||||
If you wish to automatically fix whatever clang-tidy finds _and_ is capable of fixing, add `-fix -format` to the above command:
|
||||
|
||||
```
|
||||
run-clang-tidy -p build -quiet -fix -format -allow-no-checks src tests
|
||||
run-clang-tidy -p build -quiet -fix -format -allow-no-checks include src tests
|
||||
```
|
||||
|
||||
`-format` reformats the fixed code with [`.clang-format`](./.clang-format); without it the fixes are inserted in LLVM style and the `clang-format` hook rewrites them afterwards.
|
||||
|
||||
@@ -5,15 +5,6 @@ The script determines the staged files itself (see `pass_filenames: false` in
|
||||
.pre-commit-config.yaml) so run-clang-tidy is run once and handles parallelism
|
||||
internally: pre-commit would otherwise split the files across parallel hook
|
||||
invocations that race when fixes edit a shared header.
|
||||
|
||||
Fixes are collected with `-export-fixes` and applied by clang-apply-replacements
|
||||
in a separate step rather than with run-clang-tidy's `-fix`. The `add_module`
|
||||
build isolates each module's headers behind a per-module symlink directory
|
||||
(build/modules/<module>/...), so a header reachable from several translation
|
||||
units is referenced through different paths that all resolve to the same source
|
||||
file. clang-apply-replacements deduplicates identical replacements by their
|
||||
literal path, so those paths must be canonicalised to the real source path
|
||||
first; otherwise the same fix is applied once per path and corrupts the header.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -23,7 +14,6 @@ import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
# Extensions run-clang-tidy can analyse: `.cpp` translation units and, thanks to
|
||||
@@ -31,11 +21,6 @@ from pathlib import Path
|
||||
# compile_commands.json entry). `.ipp` fragments have no entry and are skipped.
|
||||
TIDY_EXTENSIONS = {".cpp", ".h", ".hpp"}
|
||||
|
||||
# A single-quoted `FilePath:` entry in an -export-fixes YAML file, allowing the
|
||||
# `- ` marker that precedes it inside a `Replacements:` sequence. clang-tidy
|
||||
# emits paths single-quoted and doubles any embedded quote per YAML rules.
|
||||
FILEPATH_RE = re.compile(r"^(\s*(?:-\s+)?FilePath:\s*)'((?:[^']|'')*)'\s*$")
|
||||
|
||||
|
||||
def clang_tidy_major() -> str | None:
|
||||
"""Major version of the `clang-tidy` on PATH, which run-clang-tidy invokes."""
|
||||
@@ -79,25 +64,6 @@ def staged_files(repo_root: Path) -> list[Path]:
|
||||
return [repo_root / rel for rel in output.splitlines() if rel]
|
||||
|
||||
|
||||
def canonicalize_fix_paths(fixes_dir: Path) -> None:
|
||||
"""Rewrite every `FilePath` in the exported fixes to its real source path.
|
||||
|
||||
A header included through a module's isolation symlink is recorded under that
|
||||
symlink's path; collapsing all paths to the same real file lets
|
||||
clang-apply-replacements recognise the per-translation-unit duplicates and
|
||||
apply each fix once.
|
||||
"""
|
||||
for yaml in fixes_dir.glob("*.yaml"):
|
||||
lines = []
|
||||
for line in yaml.read_text().splitlines():
|
||||
if m := FILEPATH_RE.match(line):
|
||||
path = m.group(2).replace("''", "'")
|
||||
real = os.path.realpath(path).replace("'", "''")
|
||||
line = f"{m.group(1)}'{real}'"
|
||||
lines.append(line)
|
||||
yaml.write_text("\n".join(lines) + "\n")
|
||||
|
||||
|
||||
def main():
|
||||
if not os.environ.get("TIDY"):
|
||||
return 0
|
||||
@@ -116,19 +82,10 @@ def main():
|
||||
|
||||
version = clang_tidy_major()
|
||||
run_clang_tidy = find_tool("run-clang-tidy", version)
|
||||
clang_apply_replacements = find_tool("clang-apply-replacements", version)
|
||||
missing = [
|
||||
name
|
||||
for name, path in (
|
||||
("run-clang-tidy", run_clang_tidy),
|
||||
("clang-apply-replacements", clang_apply_replacements),
|
||||
)
|
||||
if not path
|
||||
]
|
||||
if missing:
|
||||
if not run_clang_tidy:
|
||||
tried = f" (tried the '-{version}' suffix too)" if version else ""
|
||||
print(
|
||||
f"clang-tidy check failed: TIDY is enabled but {' and '.join(missing)} "
|
||||
f"clang-tidy check failed: TIDY is enabled but run-clang-tidy "
|
||||
f"was not found in PATH{tried}.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
@@ -143,27 +100,19 @@ def main():
|
||||
)
|
||||
return 1
|
||||
|
||||
with tempfile.TemporaryDirectory() as fixes_dir:
|
||||
result = subprocess.run(
|
||||
[
|
||||
run_clang_tidy,
|
||||
"-quiet",
|
||||
"-p",
|
||||
build_dir,
|
||||
"-export-fixes",
|
||||
fixes_dir,
|
||||
"-allow-no-checks",
|
||||
]
|
||||
+ files
|
||||
)
|
||||
canonicalize_fix_paths(Path(fixes_dir))
|
||||
# `FormatStyle` in .clang-tidy does not reach this path,
|
||||
# so ask for the repository style here.
|
||||
applied = subprocess.run(
|
||||
[clang_apply_replacements, "--format", "--style=file", fixes_dir]
|
||||
)
|
||||
|
||||
return result.returncode or applied.returncode
|
||||
result = subprocess.run(
|
||||
[
|
||||
run_clang_tidy,
|
||||
"-quiet",
|
||||
"-p",
|
||||
build_dir,
|
||||
"-fix",
|
||||
"-format",
|
||||
"-allow-no-checks",
|
||||
]
|
||||
+ files
|
||||
)
|
||||
return result.returncode
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -34,11 +34,12 @@ include(create_symbolic_link)
|
||||
# sometimes `PUBLIC` and sometimes `PRIVATE`.
|
||||
# The Cs are all guaranteed to be unique.
|
||||
# We can guarantee a unique X per target by using
|
||||
# `${CMAKE_CURRENT_BINARY_DIR}/include/${target}`.
|
||||
# `${CMAKE_CURRENT_BINARY_DIR}/modules/${target}`.
|
||||
#
|
||||
# isolate_headers(target A B scope)
|
||||
function(isolate_headers target A B scope)
|
||||
file(RELATIVE_PATH C "${A}" "${B}")
|
||||
# Keep in sync with ExcludeHeaderFilterRegex in .clang-tidy.
|
||||
set(X "${CMAKE_CURRENT_BINARY_DIR}/modules/${target}")
|
||||
set(Y "${X}/${C}")
|
||||
cmake_path(GET Y PARENT_PATH parent)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <tests/libxrpl/protocol_autogen/TestHelpers.h>
|
||||
#include <protocol_autogen/TestHelpers.h>
|
||||
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol_autogen/ledger_entries/${name}.h>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <tests/libxrpl/protocol_autogen/TestHelpers.h>
|
||||
#include <protocol_autogen/TestHelpers.h>
|
||||
|
||||
#include <xrpl/protocol/SecretKey.h>
|
||||
#include <xrpl/protocol/Seed.h>
|
||||
|
||||
+10
-16
@@ -29,19 +29,6 @@
|
||||
#
|
||||
# verify_target_headers(target headers_dir)
|
||||
function(verify_target_headers target headers_dir)
|
||||
# .ipp files are compiled through the header or translation unit that
|
||||
# includes them, not on their own.
|
||||
file(
|
||||
GLOB_RECURSE headers
|
||||
CONFIGURE_DEPENDS
|
||||
"${headers_dir}/*.h"
|
||||
"${headers_dir}/*.hpp"
|
||||
)
|
||||
# A directory without headers has nothing to verify, and an object library
|
||||
# without sources is an error.
|
||||
if(NOT headers)
|
||||
return()
|
||||
endif()
|
||||
set(verify ${target}.verify)
|
||||
if(NOT TARGET ${verify})
|
||||
add_library(${verify} OBJECT EXCLUDE_FROM_ALL)
|
||||
@@ -67,11 +54,18 @@ function(verify_target_headers target headers_dir)
|
||||
)
|
||||
add_dependencies(verify-headers ${verify})
|
||||
endif()
|
||||
_verify_add_headers(${verify} "${headers}")
|
||||
_verify_add_headers(${verify} "${headers_dir}")
|
||||
endfunction()
|
||||
|
||||
# Add the given headers to target as directly-compiled C++ translation units.
|
||||
function(_verify_add_headers target headers)
|
||||
# Add every .h/.hpp under dir to target as a directly-compiled C++ translation
|
||||
# unit. .ipp files are inline-implementation fragments included by their owning
|
||||
# header (often after a class declaration), so they are not self-contained on
|
||||
# their own and are verified transitively when that header is verified.
|
||||
function(_verify_add_headers target dir)
|
||||
file(GLOB_RECURSE headers CONFIGURE_DEPENDS "${dir}/*.h" "${dir}/*.hpp")
|
||||
if(NOT headers)
|
||||
return()
|
||||
endif()
|
||||
# `-xc++` forces the header to be compiled as a C++ translation unit; a lone
|
||||
# `.h` is otherwise treated as a header to precompile. `#pragma once` is
|
||||
# harmless (and warns) when the header is the main file, so silence it.
|
||||
|
||||
@@ -897,7 +897,7 @@ Consensus<Adaptor>::gotTxSet(NetClock::time_point const& now, TxSetT const& txSe
|
||||
|
||||
now_ = now;
|
||||
|
||||
auto const id = txSet.id();
|
||||
auto id = txSet.id();
|
||||
|
||||
// If we've already processed this transaction set since requesting
|
||||
// it from the network, there is nothing to do now
|
||||
@@ -1624,7 +1624,7 @@ Consensus<Adaptor>::updateOurPositions(std::unique_ptr<std::stringstream> const&
|
||||
|
||||
if (ourNewSet)
|
||||
{
|
||||
auto const newID = ourNewSet->id();
|
||||
auto newID = ourNewSet->id();
|
||||
|
||||
result_->txns = std::move(*ourNewSet);
|
||||
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
#include <xrpl/basics/Number.h>
|
||||
#include <xrpl/json/json_forwards.h>
|
||||
|
||||
#include <concepts>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
@@ -198,6 +200,15 @@ public:
|
||||
*/
|
||||
Value(StaticString const& value);
|
||||
Value(std::string const& value);
|
||||
/**
|
||||
* @brief Constructs a value from a string view.
|
||||
*
|
||||
* The characters are copied, so the view need not outlive the call and need
|
||||
* not be NUL-terminated.
|
||||
*
|
||||
* @param value The characters to copy.
|
||||
*/
|
||||
Value(std::string_view value);
|
||||
Value(bool value);
|
||||
Value(Value const& other);
|
||||
~Value();
|
||||
@@ -472,6 +483,32 @@ toJson(xrpl::Number const& number)
|
||||
bool
|
||||
operator==(Value const&, Value const&);
|
||||
|
||||
/**
|
||||
* Compares a value with a string view, reading the value's characters in place
|
||||
* rather than building a Value from the view.
|
||||
*
|
||||
* Constrained to the exact type: a string literal converts equally well to a
|
||||
* view and to a Value, so a plain overload makes `value == "literal"`
|
||||
* ambiguous.
|
||||
*
|
||||
* @param x The value to compare.
|
||||
* @param y The characters to compare it against.
|
||||
* @return Whether `x` is a string whose characters up to its first NUL are
|
||||
* exactly the characters of `y`.
|
||||
*/
|
||||
template <class T>
|
||||
requires std::same_as<T, std::string_view>
|
||||
bool
|
||||
operator==(Value const& x, T y)
|
||||
{
|
||||
if (!x.isString())
|
||||
return false;
|
||||
|
||||
// A string `Value` can hold a null pointer, which names no characters, so it equals no view.
|
||||
char const* const s = x.asCString();
|
||||
return s != nullptr && std::string_view{s} == y;
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(Value const&, Value const&);
|
||||
|
||||
|
||||
@@ -6,31 +6,21 @@
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* API version numbers used in later API versions
|
||||
* The `api_version` numbers this server serves.
|
||||
*
|
||||
* Requests with a version number in the range
|
||||
* [apiMinimumSupportedVersion, apiMaximumSupportedVersion]
|
||||
* are supported.
|
||||
* A request naming a version in [kApiMinimumSupportedVersion,
|
||||
* kApiMaximumSupportedVersion] is served. With `[beta_rpc_api]` set to `1` in
|
||||
* the config the range extends to kApiBetaVersion.
|
||||
*
|
||||
* If [beta_rpc_api] is enabled in config, the version numbers
|
||||
* in the range [apiMinimumSupportedVersion, apiBetaVersion]
|
||||
* are supported.
|
||||
*
|
||||
* Network Requests without explicit version numbers use
|
||||
* apiVersionIfUnspecified. apiVersionIfUnspecified is 1,
|
||||
* because all the RPC requests with a version >= 2 must
|
||||
* explicitly specify the version in the requests.
|
||||
* Note that apiVersionIfUnspecified will be lower than
|
||||
* apiMinimumSupportedVersion when we stop supporting API
|
||||
* version 1.
|
||||
*
|
||||
* Command line Requests use apiCommandLineVersion.
|
||||
* A request naming no version is served at kApiVersionIfUnspecified, which is 1
|
||||
* because a request wanting any later version states it.
|
||||
*/
|
||||
|
||||
namespace rpc {
|
||||
@@ -57,6 +47,16 @@ static_assert(kApiMaximumSupportedVersion >= kApiMinimumSupportedVersion);
|
||||
static_assert(kApiBetaVersion >= kApiMaximumSupportedVersion);
|
||||
static_assert(kApiMaximumValidVersion >= kApiMaximumSupportedVersion);
|
||||
|
||||
/**
|
||||
* Values accepted in the `ripplerpc` request field, which selects the shape of
|
||||
* the JSON-RPC reply envelope. Distinct from `kJsonRpcVersion` in JsonRpc.h,
|
||||
* which names the JSON-RPC protocol itself, and from the `api_version`
|
||||
* constants above, which select the content of the response.
|
||||
*/
|
||||
inline constexpr std::string_view kRippleRpcVersion1{"1.0"};
|
||||
inline constexpr std::string_view kRippleRpcVersion2{"2.0"};
|
||||
inline constexpr std::string_view kRippleRpcVersion3{"3.0"};
|
||||
|
||||
inline void
|
||||
setVersion(json::Value& parent, unsigned int apiVersion, bool betaEnabled)
|
||||
{
|
||||
|
||||
@@ -144,7 +144,27 @@ enum ErrorCodeI {
|
||||
RpcEntryNotFound = 98,
|
||||
RpcUnexpectedLedgerType = 99,
|
||||
|
||||
RpcLast = RpcUnexpectedLedgerType, // rpcLAST should always equal the last code.
|
||||
// submit + simulate
|
||||
RpcInvalidTransaction = 100,
|
||||
RpcInternalSubmit = 101,
|
||||
RpcInternalJson = 102,
|
||||
RpcInternalSimulate = 103,
|
||||
|
||||
// transaction_entry
|
||||
RpcFieldNotFoundTransaction = 104,
|
||||
RpcNotYetImplemented = 105,
|
||||
RpcTransactionNotFound = 106,
|
||||
|
||||
// transaction_entry
|
||||
RpcMalformedRequest = 107,
|
||||
|
||||
// ledger_accept
|
||||
RpcNotStandAlone = 108,
|
||||
|
||||
// ledger_entry, API version 1 only
|
||||
RpcUnknownOption = 109,
|
||||
|
||||
RpcLast = RpcUnknownOption, // rpcLAST should always equal the last code.
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -180,11 +200,6 @@ struct ErrorInfo
|
||||
{
|
||||
}
|
||||
|
||||
constexpr ErrorInfo(ErrorCodeI code, char const* token, char const* message)
|
||||
: code(code), token(token), message(message), httpStatus(200)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr ErrorInfo(ErrorCodeI code, char const* token, char const* message, int httpStatus)
|
||||
: code(code), token(token), message(message), httpStatus(httpStatus)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/json/json_forwards.h>
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace xrpl::rpc {
|
||||
|
||||
/**
|
||||
* Constants of the JSON-RPC 2.0 protocol itself.
|
||||
*
|
||||
* Kept apart from the `api_version` and `ripplerpc` constants in ApiVersion.h,
|
||||
* which go when support for API versions 1 and 2 goes.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Value of the `jsonrpc` member of a request and of its reply, fixed at "2.0"
|
||||
* by the JSON-RPC specification.
|
||||
*/
|
||||
inline constexpr std::string_view kJsonRpcVersion{"2.0"};
|
||||
|
||||
/**
|
||||
* Codes for the `code` member of a JSON-RPC error object.
|
||||
*
|
||||
* The specification reserves -32768 to -32000 for the protocol and leaves
|
||||
* -32000 to -32099 of it to the implementation.
|
||||
*
|
||||
* kJsonRpcServerError is the code for an error an XRPL handler reports.
|
||||
*
|
||||
* The codes from kJsonRpcServerOverloaded on lie outside the
|
||||
* implementation-defined sub-range, which the specification does not allow.
|
||||
* They are the codes every shipped version reports, so moving one breaks the
|
||||
* clients matching on it.
|
||||
*/
|
||||
inline constexpr json::Int kJsonRpcServerError{-32000};
|
||||
inline constexpr json::Int kJsonRpcInvalidRequest{-32600};
|
||||
inline constexpr json::Int kJsonRpcMethodNotFound{-32601};
|
||||
inline constexpr json::Int kJsonRpcInvalidParams{-32602};
|
||||
inline constexpr json::Int kJsonRpcServerOverloaded{-32604};
|
||||
inline constexpr json::Int kJsonRpcForbidden{-32605};
|
||||
inline constexpr json::Int kJsonRpcWrongVersion{-32606};
|
||||
|
||||
} // namespace xrpl::rpc
|
||||
@@ -244,7 +244,7 @@ JSS(ephemeral_key); // out: ValidatorInfo
|
||||
JSS(error); // out: error
|
||||
JSS(errored); //
|
||||
JSS(error_code); // out: error
|
||||
JSS(error_exception); // out: Submit
|
||||
JSS(error_exception); // out: Submit, Simulate
|
||||
JSS(error_message); // out: error
|
||||
JSS(expand); // in: handler/Ledger
|
||||
JSS(expected_date); // out: any (warnings)
|
||||
@@ -560,7 +560,7 @@ JSS(signing_key); // out: NetworkOPs
|
||||
JSS(signing_keys); // out: ValidatorList
|
||||
JSS(signing_time); // out: NetworkOPs
|
||||
JSS(signer_lists); // in/out: AccountInfo
|
||||
JSS(size); // out: get_aggregate_price
|
||||
JSS(size); // out: get_aggregate_price, ServerHandler
|
||||
JSS(snapshot); // in: Subscribe
|
||||
JSS(source_account); // in: PathRequest, RipplePathFind
|
||||
JSS(source_amount); // in: PathRequest, RipplePathFind
|
||||
|
||||
@@ -7,6 +7,20 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* Writes an HTTP reply carrying @p strMsg with status @p nStatus to @p output,
|
||||
* and logs the status at trace. The body is not logged here: it may carry a
|
||||
* credential this library cannot mask, so the caller logs it masked.
|
||||
*
|
||||
* A 401 with an empty body is answered with the fixed authentication page.
|
||||
* The status line carries the phrase Beast's registry gives @p nStatus, except
|
||||
* for 401 and 503, which carry a phrase of this server's own.
|
||||
*
|
||||
* @param nStatus The HTTP status code.
|
||||
* @param strMsg The body.
|
||||
* @param output Where the reply bytes are written.
|
||||
* @param j The journal the status is logged to.
|
||||
*/
|
||||
void
|
||||
httpReply(int nStatus, std::string const& strMsg, json::Output const&, beast::Journal j);
|
||||
|
||||
|
||||
@@ -144,7 +144,6 @@ public:
|
||||
XRPL_ASSERT(
|
||||
view_.has_value(),
|
||||
"xrpl::ApplyContext::getApplyViewContext : view_ emplaced in constructor");
|
||||
// NOLINTNEXTLINE(bugprone-unchecked-optional-access) view_ emplaced in constructor
|
||||
return {.view = *view_, .tx = tx};
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -62,8 +62,8 @@ let
|
||||
# version-suffixed name first and fall back to a system binary on the PATH
|
||||
# when Nix doesn't provide it:
|
||||
# - Conan's Boost recipe looks up `g++-<major>` before plain `g++`.
|
||||
# - bin/pre-commit/clang_tidy_check.py looks up `run-clang-tidy-<v>` and
|
||||
# `clang-apply-replacements-<v>` before the unsuffixed names.
|
||||
# - bin/pre-commit/clang_tidy_check.py looks up `run-clang-tidy-<v>`
|
||||
# before the unsuffixed name.
|
||||
# On a host that also has the matching system binary
|
||||
# (e.g. Ubuntu's `/usr/bin/g++-<v>` or `clang-tidy-<v>`),
|
||||
# the probe escapes Nix and mixes a system tool into the Nix environment.
|
||||
|
||||
@@ -703,6 +703,11 @@ Reader::decodeString(Token& token, std::string& decoded)
|
||||
if (!decodeUnicodeCodePoint(token, current, end, unicode))
|
||||
return false;
|
||||
|
||||
// json::Value stores a string through its first NUL, so a string holding one
|
||||
// would be read as the text before it. Refuse it rather than truncate.
|
||||
if (unicode == 0)
|
||||
return addError("Null character in string", token, current);
|
||||
|
||||
decoded += codePointToUTF8(unicode);
|
||||
}
|
||||
break;
|
||||
@@ -711,6 +716,11 @@ Reader::decodeString(Token& token, std::string& decoded)
|
||||
return addError("Bad escape sequence in string", token, current);
|
||||
}
|
||||
}
|
||||
else if (c == '\0')
|
||||
{
|
||||
// The raw form of the escape refused above.
|
||||
return addError("Null character in string", token, current);
|
||||
}
|
||||
else
|
||||
{
|
||||
decoded += c;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
namespace json {
|
||||
@@ -241,10 +242,14 @@ Value::Value(xrpl::Number const& value) : type_(ValueType::String), allocated_(t
|
||||
value_.stringVal = valueAllocator()->duplicateStringValue(tmp.c_str(), tmp.length());
|
||||
}
|
||||
|
||||
Value::Value(std::string const& value) : type_(ValueType::String), allocated_(true)
|
||||
Value::Value(std::string const& value) : Value(std::string_view{value})
|
||||
{
|
||||
value_.stringVal =
|
||||
valueAllocator()->duplicateStringValue(value.c_str(), (unsigned int)value.length());
|
||||
}
|
||||
|
||||
Value::Value(std::string_view value) : type_(ValueType::String), allocated_(true)
|
||||
{
|
||||
value_.stringVal = valueAllocator()->duplicateStringValue(
|
||||
value.data(), static_cast<unsigned int>(value.length()));
|
||||
}
|
||||
|
||||
Value::Value(StaticString const& value) : type_(ValueType::String)
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
@@ -363,12 +364,22 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the status line and headers of the reply, then the body.
|
||||
*
|
||||
* @param ecResult The outcome of the read that delivered the header.
|
||||
* @param bytesTransferred The length of the header through its `\r\n\r\n`
|
||||
* delimiter; the buffer can hold body bytes read past it.
|
||||
*/
|
||||
void
|
||||
handleHeader(boost::system::error_code const& ecResult, std::size_t bytesTransferred)
|
||||
{
|
||||
std::string strHeader{
|
||||
{std::istreambuf_iterator<char>(&header_)}, std::istreambuf_iterator<char>()};
|
||||
JLOG(j_.trace()) << "Header: \"" << strHeader << "\"";
|
||||
// The trace covers the header only: the bytes read past the delimiter are body, which can
|
||||
// carry a credential.
|
||||
JLOG(j_.trace()) << "Header: \"" << std::string_view{strHeader}.substr(0, bytesTransferred)
|
||||
<< "\"";
|
||||
|
||||
static boost::regex const kReStatus{R"(\`HTTP/1\S+ (\d{3}) .*\')"}; // HTTP/1.1 200 OK
|
||||
static boost::regex const kReSize{
|
||||
|
||||
@@ -20,88 +20,102 @@ namespace detail {
|
||||
// will remain in the object file. But the string literals will remain.
|
||||
//
|
||||
// There's a certain amount of tension in determining the correct HTTP
|
||||
// status to associate with a given RPC error. Initially all RPC errors
|
||||
// returned 200 (OK). And that's the default behavior if no HTTP status code
|
||||
// is specified below.
|
||||
// status to associate with a given RPC error. Every row below names its
|
||||
// HTTP status, and a row that omits it does not compile, since ErrorInfo has
|
||||
// no constructor that leaves the status out.
|
||||
//
|
||||
// The codes currently selected target the load balancer fail-over use case.
|
||||
// If a query fails on one node but is likely to have a positive outcome
|
||||
// on a different node, then the failure should return a 4xx/5xx range
|
||||
// status code.
|
||||
|
||||
// The rows below are aligned by hand into four columns, so that a wrong status or a mistyped token
|
||||
// is visible by scanning one column. That cannot be had inside the 100-column limit once the
|
||||
// longest enumerator and the longest message sit in one row. So this region is exempt from the
|
||||
// limit by design rather than by oversight.
|
||||
// clang-format off
|
||||
static constexpr ErrorInfo kUnorderedErrorInfos[]{
|
||||
{RpcActMalformed, "actMalformed", "Account malformed."},
|
||||
{RpcActNotFound, "actNotFound", "Account not found."},
|
||||
{RpcAlreadyMultisig, "alreadyMultisig", "Already multisigned."},
|
||||
{RpcAlreadySingleSig, "alreadySingleSig", "Already single-signed."},
|
||||
{RpcAmendmentBlocked, "amendmentBlocked", "Amendment blocked, need upgrade.", 503},
|
||||
{RpcExpiredValidatorList, "unlBlocked", "Validator list expired.", 503},
|
||||
{RpcAtxDeprecated, "deprecated", "Use the new API or specify a ledger range.", 400},
|
||||
{RpcBadKeyType, "badKeyType", "Bad key type.", 400},
|
||||
{RpcBadFeature, "badFeature", "Feature unknown or invalid.", 500},
|
||||
{RpcBadIssuer, "badIssuer", "Issuer account malformed.", 400},
|
||||
{RpcBadMarket, "badMarket", "No such market.", 404},
|
||||
{RpcBadSecret, "badSecret", "Secret does not match account.", 403},
|
||||
{RpcBadSeed, "badSeed", "Disallowed seed.", 403},
|
||||
{RpcBadSyntax, "badSyntax", "Syntax error.", 400},
|
||||
{RpcChannelMalformed, "channelMalformed", "Payment channel is malformed.", 400},
|
||||
{RpcChannelAmtMalformed, "channelAmtMalformed", "Payment channel amount is malformed.", 400},
|
||||
{RpcCommandMissing, "commandMissing", "Missing command entry.", 400},
|
||||
{RpcDbDeserialization, "dbDeserialization", "Database deserialization error.", 502},
|
||||
{RpcDstActMalformed, "dstActMalformed", "Destination account is malformed.", 400},
|
||||
{RpcDstActMissing, "dstActMissing", "Destination account not provided.", 400},
|
||||
{RpcDstActNotFound, "dstActNotFound", "Destination account not found.", 404},
|
||||
{RpcDstAmtMalformed, "dstAmtMalformed", "Destination amount/currency/issuer is malformed.", 400},
|
||||
{RpcDstAmtMissing, "dstAmtMissing", "Destination amount/currency/issuer is missing.", 400},
|
||||
{RpcDstIsrMalformed, "dstIsrMalformed", "Destination issuer is malformed.", 400},
|
||||
{RpcExcessiveLgrRange, "excessiveLgrRange", "Ledger range exceeds 1000.", 400},
|
||||
{RpcForbidden, "forbidden", "Bad credentials.", 403},
|
||||
{RpcHighFee, "highFee", "Current transaction fee exceeds your limit.", 402},
|
||||
{RpcInternal, "internal", "Internal error.", 500},
|
||||
{RpcInvalidLgrRange, "invalidLgrRange", "Ledger range is invalid.", 400},
|
||||
{RpcInvalidParams, "invalidParams", "Invalid parameters.", 400},
|
||||
{RpcInvalidHotwallet, "invalidHotWallet", "Invalid hotwallet.", 400},
|
||||
{RpcIssueMalformed, "issueMalformed", "Issue is malformed.", 400},
|
||||
{RpcJsonRpc, "json_rpc", "JSON-RPC transport error.", 500},
|
||||
{RpcLgrIdxsInvalid, "lgrIdxsInvalid", "Ledger indexes invalid.", 400},
|
||||
{RpcLgrIdxMalformed, "lgrIdxMalformed", "Ledger index malformed.", 400},
|
||||
{RpcLgrNotFound, "lgrNotFound", "Ledger not found.", 404},
|
||||
{RpcLgrNotValidated, "lgrNotValidated", "Ledger not validated.", 202},
|
||||
{RpcMasterDisabled, "masterDisabled", "Master key is disabled.", 403},
|
||||
{RpcNotEnabled, "notEnabled", "Not enabled in configuration.", 501},
|
||||
{RpcNotImpl, "notImpl", "Not implemented.", 501},
|
||||
{RpcNotReady, "notReady", "Not ready to handle this request.", 503},
|
||||
{RpcNotSupported, "notSupported", "Operation not supported.", 501},
|
||||
{RpcNoClosed, "noClosed", "Closed ledger is unavailable.", 503},
|
||||
{RpcNoCurrent, "noCurrent", "Current ledger is unavailable.", 503},
|
||||
{RpcNotSynced, "notSynced", "Not synced to the network.", 503},
|
||||
{RpcNoEvents, "noEvents", "Current transport does not support events.", 405},
|
||||
{RpcNoNetwork, "noNetwork", "Not synced to the network.", 503},
|
||||
{RpcWrongNetwork, "wrongNetwork", "Wrong network.", 503},
|
||||
{RpcNoPermission, "noPermission", "You don't have permission for this command.", 401},
|
||||
{RpcNoPfRequest, "noPathRequest", "No pathfinding request in progress.", 404},
|
||||
{RpcObjectNotFound, "objectNotFound", "The requested object was not found.", 404},
|
||||
{RpcPublicMalformed, "publicMalformed", "Public key is malformed.", 400},
|
||||
{RpcSendmaxMalformed, "sendMaxMalformed", "SendMax amount malformed.", 400},
|
||||
{RpcSigningMalformed, "signingMalformed", "Signing of transaction is malformed.", 400},
|
||||
{RpcSlowDown, "slowDown", "You are placing too much load on the server.", 429},
|
||||
{RpcSrcActMalformed, "srcActMalformed", "Source account is malformed.", 400},
|
||||
{RpcSrcActMissing, "srcActMissing", "Source account not provided.", 400},
|
||||
{RpcSrcActNotFound, "srcActNotFound", "Source account not found.", 404},
|
||||
{RpcDelegateActNotFound, "delegateActNotFound", "Delegate account not found.", 404},
|
||||
{RpcSrcCurMalformed, "srcCurMalformed", "Source currency is malformed.", 400},
|
||||
{RpcSrcIsrMalformed, "srcIsrMalformed", "Source issuer is malformed.", 400},
|
||||
{RpcStreamMalformed, "malformedStream", "Stream malformed.", 400},
|
||||
{RpcTooBusy, "tooBusy", "The server is too busy to help you now.", 503},
|
||||
{RpcTxnNotFound, "txnNotFound", "Transaction not found.", 404},
|
||||
{RpcUnknownCommand, "unknownCmd", "Unknown method.", 405},
|
||||
{RpcOracleMalformed, "oracleMalformed", "Oracle request is malformed.", 400},
|
||||
{RpcBadCredentials, "badCredentials", "Credentials do not exist, are not accepted, or have expired.", 400},
|
||||
{RpcTxSigned, "transactionSigned", "Transaction should not be signed.", 400},
|
||||
{RpcDomainMalformed, "domainMalformed", "Domain is malformed.", 400},
|
||||
{RpcEntryNotFound, "entryNotFound", "Entry not found.", 400},
|
||||
{RpcUnexpectedLedgerType, "unexpectedLedgerType", "Unexpected ledger type.", 400},
|
||||
{RpcActMalformed, "actMalformed", "Account malformed.", 400},
|
||||
{RpcActNotFound, "actNotFound", "Account not found.", 404},
|
||||
{RpcAlreadyMultisig, "alreadyMultisig", "Already multisigned.", 400},
|
||||
{RpcAlreadySingleSig, "alreadySingleSig", "Already single-signed.", 400},
|
||||
{RpcAmendmentBlocked, "amendmentBlocked", "Amendment blocked, need upgrade.", 503},
|
||||
{RpcExpiredValidatorList, "unlBlocked", "Validator list expired.", 503},
|
||||
{RpcAtxDeprecated, "deprecated", "Use the new API or specify a ledger range.", 400},
|
||||
{RpcBadKeyType, "badKeyType", "Bad key type.", 400},
|
||||
{RpcBadFeature, "badFeature", "Feature unknown or invalid.", 500},
|
||||
{RpcBadIssuer, "badIssuer", "Issuer account malformed.", 400},
|
||||
{RpcBadMarket, "badMarket", "No such market.", 404},
|
||||
{RpcBadSecret, "badSecret", "Secret does not match account.", 403},
|
||||
{RpcBadSeed, "badSeed", "Disallowed seed.", 403},
|
||||
{RpcBadSyntax, "badSyntax", "Syntax error.", 400},
|
||||
{RpcChannelMalformed, "channelMalformed", "Payment channel is malformed.", 400},
|
||||
{RpcChannelAmtMalformed, "channelAmtMalformed", "Payment channel amount is malformed.", 400},
|
||||
{RpcCommandMissing, "commandMissing", "Missing command entry.", 400},
|
||||
{RpcDbDeserialization, "dbDeserialization", "Database deserialization error.", 502},
|
||||
{RpcDstActMalformed, "dstActMalformed", "Destination account is malformed.", 400},
|
||||
{RpcDstActMissing, "dstActMissing", "Destination account not provided.", 400},
|
||||
{RpcDstActNotFound, "dstActNotFound", "Destination account not found.", 404},
|
||||
{RpcDstAmtMalformed, "dstAmtMalformed", "Destination amount/currency/issuer is malformed.", 400},
|
||||
{RpcDstAmtMissing, "dstAmtMissing", "Destination amount/currency/issuer is missing.", 400},
|
||||
{RpcDstIsrMalformed, "dstIsrMalformed", "Destination issuer is malformed.", 400},
|
||||
{RpcExcessiveLgrRange, "excessiveLgrRange", "Ledger range exceeds 1000.", 400},
|
||||
{RpcForbidden, "forbidden", "Bad credentials.", 403},
|
||||
{RpcHighFee, "highFee", "Current transaction fee exceeds your limit.", 402},
|
||||
{RpcInternal, "internal", "Internal error.", 500},
|
||||
{RpcInvalidLgrRange, "invalidLgrRange", "Ledger range is invalid.", 400},
|
||||
{RpcInvalidParams, "invalidParams", "Invalid parameters.", 400},
|
||||
{RpcInvalidHotwallet, "invalidHotWallet", "Invalid hotwallet.", 400},
|
||||
{RpcIssueMalformed, "issueMalformed", "Issue is malformed.", 400},
|
||||
{RpcJsonRpc, "json_rpc", "JSON-RPC transport error.", 500},
|
||||
{RpcLgrIdxsInvalid, "lgrIdxsInvalid", "Ledger indexes invalid.", 400},
|
||||
{RpcLgrIdxMalformed, "lgrIdxMalformed", "Ledger index malformed.", 400},
|
||||
{RpcLgrNotFound, "lgrNotFound", "Ledger not found.", 404},
|
||||
{RpcLgrNotValidated, "lgrNotValidated", "Ledger not validated.", 202},
|
||||
{RpcMasterDisabled, "masterDisabled", "Master key is disabled.", 403},
|
||||
{RpcNotEnabled, "notEnabled", "Not enabled in configuration.", 501},
|
||||
{RpcNotImpl, "notImpl", "Not implemented.", 501},
|
||||
{RpcNotReady, "notReady", "Not ready to handle this request.", 503},
|
||||
{RpcNotSupported, "notSupported", "Operation not supported.", 501},
|
||||
{RpcNoClosed, "noClosed", "Closed ledger is unavailable.", 503},
|
||||
{RpcNoCurrent, "noCurrent", "Current ledger is unavailable.", 503},
|
||||
{RpcNotSynced, "notSynced", "Not synced to the network.", 503},
|
||||
{RpcNoEvents, "noEvents", "Current transport does not support events.", 405},
|
||||
{RpcNoNetwork, "noNetwork", "Not synced to the network.", 503},
|
||||
{RpcWrongNetwork, "wrongNetwork", "Wrong network.", 503},
|
||||
{RpcNoPermission, "noPermission", "You don't have permission for this command.", 401},
|
||||
{RpcNoPfRequest, "noPathRequest", "No pathfinding request in progress.", 404},
|
||||
{RpcObjectNotFound, "objectNotFound", "The requested object was not found.", 404},
|
||||
{RpcPublicMalformed, "publicMalformed", "Public key is malformed.", 400},
|
||||
{RpcSendmaxMalformed, "sendMaxMalformed", "SendMax amount malformed.", 400},
|
||||
{RpcSigningMalformed, "signingMalformed", "Signing of transaction is malformed.", 400},
|
||||
{RpcSlowDown, "slowDown", "You are placing too much load on the server.", 429},
|
||||
{RpcSrcActMalformed, "srcActMalformed", "Source account is malformed.", 400},
|
||||
{RpcSrcActMissing, "srcActMissing", "Source account not provided.", 400},
|
||||
{RpcSrcActNotFound, "srcActNotFound", "Source account not found.", 404},
|
||||
{RpcDelegateActNotFound, "delegateActNotFound", "Delegate account not found.", 404},
|
||||
{RpcSrcCurMalformed, "srcCurMalformed", "Source currency is malformed.", 400},
|
||||
{RpcSrcIsrMalformed, "srcIsrMalformed", "Source issuer is malformed.", 400},
|
||||
{RpcStreamMalformed, "malformedStream", "Stream malformed.", 400},
|
||||
{RpcTooBusy, "tooBusy", "The server is too busy to help you now.", 503},
|
||||
{RpcTxnNotFound, "txnNotFound", "Transaction not found.", 404},
|
||||
{RpcUnknownCommand, "unknownCmd", "Unknown method.", 405},
|
||||
{RpcOracleMalformed, "oracleMalformed", "Oracle request is malformed.", 400},
|
||||
{RpcBadCredentials, "badCredentials", "Credentials do not exist, are not accepted, or have expired.", 400},
|
||||
{RpcTxSigned, "transactionSigned", "Transaction should not be signed.", 400},
|
||||
{RpcDomainMalformed, "domainMalformed", "Domain is malformed.", 400},
|
||||
{RpcEntryNotFound, "entryNotFound", "Entry not found.", 400},
|
||||
{RpcUnexpectedLedgerType, "unexpectedLedgerType", "Unexpected ledger type.", 400},
|
||||
{RpcInvalidTransaction, "invalidTransaction", "Transaction is invalid.", 400},
|
||||
{RpcInternalSubmit, "internalSubmit", "Internal error during submit.", 500},
|
||||
{RpcInternalJson, "internalJson", "Internal error during JSON handling.", 500},
|
||||
{RpcInternalSimulate, "internalSimulate", "Internal error during simulate.", 500},
|
||||
{RpcFieldNotFoundTransaction, "fieldNotFoundTransaction", "Missing required field.", 400},
|
||||
{RpcNotYetImplemented, "notYetImplemented", "Not yet implemented.", 501},
|
||||
{RpcTransactionNotFound, "transactionNotFound", "Transaction not found.", 404},
|
||||
{RpcMalformedRequest, "malformedRequest", "Request is malformed.", 400},
|
||||
{RpcNotStandAlone, "notStandAlone", "Server is not running stand-alone.", 501},
|
||||
{RpcUnknownOption, "unknownOption", "Unknown option.", 400},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -6,7 +6,10 @@
|
||||
#include <xrpl/protocol/BuildInfo.h>
|
||||
#include <xrpl/protocol/SystemParameters.h>
|
||||
|
||||
#include <boost/beast/http/status.hpp>
|
||||
|
||||
#include <ctime>
|
||||
#include <format>
|
||||
#include <string>
|
||||
|
||||
namespace xrpl {
|
||||
@@ -33,7 +36,10 @@ getHTTPHeaderTimestamp()
|
||||
void
|
||||
httpReply(int nStatus, std::string const& content, json::Output const& output, beast::Journal j)
|
||||
{
|
||||
JLOG(j.trace()) << "HTTP Reply " << nStatus << " " << content;
|
||||
// The status only. The body is a reply, which carries a credential when the
|
||||
// command is a keygen, and this library cannot mask one: the caller logs the
|
||||
// masked body at debug.
|
||||
JLOG(j.trace()) << "HTTP Reply " << nStatus;
|
||||
|
||||
if (content.empty() && nStatus == 401)
|
||||
{
|
||||
@@ -69,42 +75,29 @@ httpReply(int nStatus, std::string const& content, json::Output const& output, b
|
||||
return;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(bugprone-switch-missing-default-case)
|
||||
switch (nStatus)
|
||||
{
|
||||
// The status every successful reply carries, so a literal rather than a format call.
|
||||
case 200:
|
||||
output("HTTP/1.1 200 OK\r\n");
|
||||
break;
|
||||
case 202:
|
||||
output("HTTP/1.1 202 Accepted\r\n");
|
||||
break;
|
||||
case 400:
|
||||
output("HTTP/1.1 400 Bad Request\r\n");
|
||||
break;
|
||||
// Two statuses this server phrases itself rather than taking from the registry.
|
||||
case 401:
|
||||
output("HTTP/1.1 401 Authorization Required\r\n");
|
||||
break;
|
||||
case 403:
|
||||
output("HTTP/1.1 403 Forbidden\r\n");
|
||||
break;
|
||||
case 404:
|
||||
output("HTTP/1.1 404 Not Found\r\n");
|
||||
break;
|
||||
case 405:
|
||||
output("HTTP/1.1 405 Method Not Allowed\r\n");
|
||||
break;
|
||||
case 429:
|
||||
output("HTTP/1.1 429 Too Many Requests\r\n");
|
||||
break;
|
||||
case 500:
|
||||
output("HTTP/1.1 500 Internal Server Error\r\n");
|
||||
break;
|
||||
case 501:
|
||||
output("HTTP/1.1 501 Not Implemented\r\n");
|
||||
break;
|
||||
case 503:
|
||||
output("HTTP/1.1 503 Server is overloaded\r\n");
|
||||
break;
|
||||
default:
|
||||
// A reply whose first line is a header is not an HTTP response. Beast knows the whole
|
||||
// registry, so a status the error table gains needs no case here.
|
||||
output(
|
||||
std::format(
|
||||
"HTTP/1.1 {} {}\r\n",
|
||||
nStatus,
|
||||
boost::beast::http::obsolete_reason(
|
||||
static_cast<boost::beast::http::status>(nStatus))));
|
||||
break;
|
||||
}
|
||||
|
||||
output(getHTTPHeaderTimestamp());
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <test/jtx/PeerStub.h>
|
||||
#include <tests/libxrpl/shamap/DeepChain.h>
|
||||
|
||||
#include <xrpld/app/ledger/ConsensusTransSetSF.h>
|
||||
#include <xrpld/overlay/Peer.h>
|
||||
@@ -15,6 +14,8 @@
|
||||
#include <xrpl/shamap/SHAMapNodeID.h>
|
||||
#include <xrpl/shamap/SHAMapTreeNode.h>
|
||||
|
||||
#include <tests/libxrpl/shamap/DeepChain.h>
|
||||
|
||||
#include <xrpl.pb.h>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
@@ -2801,7 +2801,8 @@ class Batch_test : public beast::unit_test::Suite
|
||||
auto const jrr = env.rpc("submit", strHex(slice))[jss::result];
|
||||
expect(
|
||||
jrr[jss::status] == "error" && jrr[jss::error] == "invalidTransaction" &&
|
||||
!jrr.isMember(jss::error_code) && jrr[jss::error_message].isNull() &&
|
||||
jrr[jss::error_code] == RpcInvalidTransaction &&
|
||||
jrr[jss::error_message] == "Transaction is invalid." &&
|
||||
jrr[jss::error_exception] ==
|
||||
"fails local checks: Batch inner transactions are never "
|
||||
"considered validly signed.",
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <xrpl/ledger/OpenView.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/ConfidentialTransfer.h>
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
@@ -7944,8 +7945,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase
|
||||
// Signature verification fails — rejected before ZKP check
|
||||
auto const jr = env.rpc("submit", strHex(tampered.slice()));
|
||||
BEAST_EXPECT(jr[jss::result][jss::error] == "invalidTransaction");
|
||||
BEAST_EXPECT(!jr[jss::result].isMember(jss::error_code));
|
||||
BEAST_EXPECT(jr[jss::result][jss::error_message].isNull());
|
||||
BEAST_EXPECT(jr[jss::result][jss::error_code] == RpcInvalidTransaction);
|
||||
BEAST_EXPECT(jr[jss::result][jss::error_message] == "Transaction is invalid.");
|
||||
}
|
||||
|
||||
// Variant B: Re-signed with inflated ciphertext.
|
||||
@@ -8053,8 +8054,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase
|
||||
|
||||
auto const jr = env.rpc("submit", strHex(tampered.slice()));
|
||||
BEAST_EXPECT(jr[jss::result][jss::error] == "invalidTransaction");
|
||||
BEAST_EXPECT(!jr[jss::result].isMember(jss::error_code));
|
||||
BEAST_EXPECT(jr[jss::result][jss::error_message].isNull());
|
||||
BEAST_EXPECT(jr[jss::result][jss::error_code] == RpcInvalidTransaction);
|
||||
BEAST_EXPECT(jr[jss::result][jss::error_message] == "Transaction is invalid.");
|
||||
}
|
||||
|
||||
// Variant B: Re-signed with all negated ciphertexts.
|
||||
@@ -8158,8 +8159,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase
|
||||
|
||||
auto const jr = env.rpc("submit", strHex(tampered.slice()));
|
||||
BEAST_EXPECT(jr[jss::result][jss::error] == "invalidTransaction");
|
||||
BEAST_EXPECT(!jr[jss::result].isMember(jss::error_code));
|
||||
BEAST_EXPECT(jr[jss::result][jss::error_message].isNull());
|
||||
BEAST_EXPECT(jr[jss::result][jss::error_code] == RpcInvalidTransaction);
|
||||
BEAST_EXPECT(jr[jss::result][jss::error_message] == "Transaction is invalid.");
|
||||
}
|
||||
|
||||
// Variant B: Re-signed with combined ciphertext.
|
||||
@@ -8284,8 +8285,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase
|
||||
// Signature verification fails
|
||||
auto const jr = env.rpc("submit", strHex(tampered.slice()));
|
||||
BEAST_EXPECT(jr[jss::result][jss::error] == "invalidTransaction");
|
||||
BEAST_EXPECT(!jr[jss::result].isMember(jss::error_code));
|
||||
BEAST_EXPECT(jr[jss::result][jss::error_message].isNull());
|
||||
BEAST_EXPECT(jr[jss::result][jss::error_code] == RpcInvalidTransaction);
|
||||
BEAST_EXPECT(jr[jss::result][jss::error_message] == "Transaction is invalid.");
|
||||
}
|
||||
|
||||
// Variant B: Re-signed C1 substitution.
|
||||
@@ -8376,8 +8377,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase
|
||||
// signed — transaction rejected before ZKP verification.
|
||||
auto const jr = env.rpc("submit", strHex(tampered.slice()));
|
||||
BEAST_EXPECT(jr[jss::result][jss::error] == "invalidTransaction");
|
||||
BEAST_EXPECT(!jr[jss::result].isMember(jss::error_code));
|
||||
BEAST_EXPECT(jr[jss::result][jss::error_message].isNull());
|
||||
BEAST_EXPECT(jr[jss::result][jss::error_code] == RpcInvalidTransaction);
|
||||
BEAST_EXPECT(jr[jss::result][jss::error_message] == "Transaction is invalid.");
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
@@ -1946,8 +1946,8 @@ class MPToken_test : public beast::unit_test::Suite
|
||||
jtx.stx->add(s);
|
||||
auto jrr = env.rpc("submit", strHex(s.slice()));
|
||||
BEAST_EXPECT(jrr[jss::result][jss::error] == "invalidTransaction");
|
||||
BEAST_EXPECT(!jrr[jss::result].isMember(jss::error_code));
|
||||
BEAST_EXPECT(jrr[jss::result][jss::error_message].isNull());
|
||||
BEAST_EXPECT(jrr[jss::result][jss::error_code] == RpcInvalidTransaction);
|
||||
BEAST_EXPECT(jrr[jss::result][jss::error_message] == "Transaction is invalid.");
|
||||
|
||||
// tx is unsigned
|
||||
json::Value jv1;
|
||||
|
||||
@@ -1080,8 +1080,8 @@ public:
|
||||
local.setFieldVL(sfSigningPubKey, Blob()); // Empty SigningPubKey
|
||||
auto const info = submitSTTx(local);
|
||||
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
|
||||
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
|
||||
BEAST_EXPECT(info[jss::result][jss::error_code] == RpcInvalidTransaction);
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message] == "Transaction is invalid.");
|
||||
BEAST_EXPECT(
|
||||
info[jss::result][jss::error_exception] ==
|
||||
"fails local checks: Empty SigningPubKey.");
|
||||
@@ -1097,8 +1097,8 @@ public:
|
||||
// Signature should fail.
|
||||
auto const info = submitSTTx(local);
|
||||
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
|
||||
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
|
||||
BEAST_EXPECT(info[jss::result][jss::error_code] == RpcInvalidTransaction);
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message] == "Transaction is invalid.");
|
||||
BEAST_EXPECT(
|
||||
info[jss::result][jss::error_exception] ==
|
||||
"fails local checks: Invalid signature.");
|
||||
@@ -1113,8 +1113,8 @@ public:
|
||||
// Signature should fail.
|
||||
auto const info = submitSTTx(local);
|
||||
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
|
||||
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
|
||||
BEAST_EXPECT(info[jss::result][jss::error_code] == RpcInvalidTransaction);
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message] == "Transaction is invalid.");
|
||||
BEAST_EXPECT(
|
||||
info[jss::result][jss::error_exception] ==
|
||||
"fails local checks: Invalid signature.");
|
||||
@@ -1126,8 +1126,8 @@ public:
|
||||
local[sfSigningPubKey] = alice.pk(); // Insert sfSigningPubKey
|
||||
auto const info = submitSTTx(local);
|
||||
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
|
||||
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
|
||||
BEAST_EXPECT(info[jss::result][jss::error_code] == RpcInvalidTransaction);
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message] == "Transaction is invalid.");
|
||||
BEAST_EXPECT(
|
||||
info[jss::result][jss::error_exception] ==
|
||||
"fails local checks: Cannot both single- and multi-sign.");
|
||||
@@ -1140,8 +1140,8 @@ public:
|
||||
local.setFieldVL(sfSigningPubKey, Blob()); // Empty SigningPubKey
|
||||
auto const info = submitSTTx(local);
|
||||
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
|
||||
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
|
||||
BEAST_EXPECT(info[jss::result][jss::error_code] == RpcInvalidTransaction);
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message] == "Transaction is invalid.");
|
||||
BEAST_EXPECT(
|
||||
info[jss::result][jss::error_exception] ==
|
||||
"fails local checks: Cannot both single- and multi-sign.");
|
||||
@@ -1158,8 +1158,8 @@ public:
|
||||
// Signature should fail.
|
||||
auto const info = submitSTTx(local);
|
||||
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
|
||||
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
|
||||
BEAST_EXPECT(info[jss::result][jss::error_code] == RpcInvalidTransaction);
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message] == "Transaction is invalid.");
|
||||
BEAST_EXPECT(
|
||||
info[jss::result][jss::error_exception].asString().contains(
|
||||
"Invalid signature on account r"));
|
||||
@@ -1171,8 +1171,8 @@ public:
|
||||
local.peekFieldArray(sfSigners).clear(); // Empty Signers array.
|
||||
auto const info = submitSTTx(local);
|
||||
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
|
||||
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
|
||||
BEAST_EXPECT(info[jss::result][jss::error_code] == RpcInvalidTransaction);
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message] == "Transaction is invalid.");
|
||||
BEAST_EXPECT(
|
||||
info[jss::result][jss::error_exception] ==
|
||||
"fails local checks: Invalid Signers array size.");
|
||||
@@ -1219,8 +1219,8 @@ public:
|
||||
STTx const local = *tx.stx;
|
||||
auto const info = submitSTTx(local);
|
||||
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
|
||||
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
|
||||
BEAST_EXPECT(info[jss::result][jss::error_code] == RpcInvalidTransaction);
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message] == "Transaction is invalid.");
|
||||
BEAST_EXPECT(
|
||||
info[jss::result][jss::error_exception] ==
|
||||
"fails local checks: Invalid Signers array size.");
|
||||
@@ -1231,8 +1231,8 @@ public:
|
||||
STTx const local = *tx.stx;
|
||||
auto const info = submitSTTx(local);
|
||||
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
|
||||
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
|
||||
BEAST_EXPECT(info[jss::result][jss::error_code] == RpcInvalidTransaction);
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message] == "Transaction is invalid.");
|
||||
BEAST_EXPECT(
|
||||
info[jss::result][jss::error_exception] ==
|
||||
"fails local checks: Invalid multisigner.");
|
||||
@@ -1243,8 +1243,8 @@ public:
|
||||
STTx const local = *tx.stx;
|
||||
auto const info = submitSTTx(local);
|
||||
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
|
||||
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
|
||||
BEAST_EXPECT(info[jss::result][jss::error_code] == RpcInvalidTransaction);
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message] == "Transaction is invalid.");
|
||||
BEAST_EXPECT(
|
||||
info[jss::result][jss::error_exception] ==
|
||||
"fails local checks: Duplicate Signers not allowed.");
|
||||
@@ -1259,8 +1259,8 @@ public:
|
||||
// Signature should fail.
|
||||
auto const info = submitSTTx(local);
|
||||
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
|
||||
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
|
||||
BEAST_EXPECT(info[jss::result][jss::error_code] == RpcInvalidTransaction);
|
||||
BEAST_EXPECT(info[jss::result][jss::error_message] == "Transaction is invalid.");
|
||||
BEAST_EXPECT(
|
||||
info[jss::result][jss::error_exception] ==
|
||||
"fails local checks: Unsorted Signers array.");
|
||||
|
||||
@@ -3286,8 +3286,7 @@ public:
|
||||
BEAST_EXPECT(jrr[jss::result][jss::engine_result] == "tesSUCCESS");
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jrr.isMember(jss::jsonrpc) && jrr[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jrr.isMember(jss::ripplerpc) && jrr[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jrr));
|
||||
BEAST_EXPECT(jrr.isMember(jss::id) && jrr[jss::id] == 5);
|
||||
}
|
||||
|
||||
|
||||
@@ -2269,8 +2269,7 @@ public:
|
||||
BEAST_EXPECT(jrr[jss::result][jss::engine_result] == "tesSUCCESS");
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jrr.isMember(jss::jsonrpc) && jrr[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jrr.isMember(jss::ripplerpc) && jrr[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jrr));
|
||||
BEAST_EXPECT(jrr.isMember(jss::id) && jrr[jss::id] == 5);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
@@ -1154,8 +1155,8 @@ class LoanBroker_test : public beast::unit_test::Suite
|
||||
auto const jrr = env.rpc("submit", strHex(s.slice()))[jss::result];
|
||||
// fails in doSubmit() on STTx construction
|
||||
BEAST_EXPECT(jrr[jss::error] == "invalidTransaction");
|
||||
BEAST_EXPECT(!jrr.isMember(jss::error_code));
|
||||
BEAST_EXPECT(jrr[jss::error_message].isNull());
|
||||
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidTransaction);
|
||||
BEAST_EXPECT(jrr[jss::error_message] == "Transaction is invalid.");
|
||||
BEAST_EXPECT(jrr[jss::error_exception] == "invalid native account");
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <xrpl/beast/unit_test/suite.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/json/to_string.h>
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/HashPrefix.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
@@ -190,8 +191,8 @@ private:
|
||||
BEAST_EXPECT(jr.isMember(jss::result));
|
||||
auto const jResult = jr[jss::result];
|
||||
BEAST_EXPECT(jResult[jss::error] == "invalidTransaction");
|
||||
BEAST_EXPECT(!jResult.isMember(jss::error_code));
|
||||
BEAST_EXPECT(jResult[jss::error_message].isNull());
|
||||
BEAST_EXPECT(jResult[jss::error_code] == RpcInvalidTransaction);
|
||||
BEAST_EXPECT(jResult[jss::error_message] == "Transaction is invalid.");
|
||||
BEAST_EXPECT(
|
||||
jResult[jss::error_exception] ==
|
||||
"fails local checks: Transaction has bad signature.");
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/json/to_string.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
@@ -196,8 +197,9 @@ private:
|
||||
jvResult[jss::tx_blob] = strHex(local.getSerializer().slice());
|
||||
auto res = env.rpc("json", "submit", to_string(jvResult))["result"];
|
||||
BEAST_EXPECT(
|
||||
res[jss::error] == "invalidTransaction" && !res.isMember(jss::error_code) &&
|
||||
res[jss::error_message].isNull() &&
|
||||
res[jss::error] == "invalidTransaction" &&
|
||||
res[jss::error_code] == RpcInvalidTransaction &&
|
||||
res[jss::error_message] == "Transaction is invalid." &&
|
||||
res[jss::error_exception] ==
|
||||
"fails local checks: Counterparty: Invalid signature.");
|
||||
});
|
||||
|
||||
@@ -0,0 +1,512 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpld/app/consensus/RCLCxPeerPos.h>
|
||||
|
||||
#include <xrpl/basics/UnorderedContainers.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Book.h>
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
#include <xrpl/protocol/STValidation.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
#include <xrpl/server/InfoSub.h>
|
||||
#include <xrpl/server/Manifest.h>
|
||||
#include <xrpl/server/NetworkOPs.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
/**
|
||||
* A `NetworkOPs` whose every method is a no-op returning a default.
|
||||
*
|
||||
* It exists so a handler test can supply its own operations object through
|
||||
* `rpc::Context::netOps`: derive from this and override only the methods the
|
||||
* test cares about. Adding a method to `NetworkOPs` or `InfoSub::Source` then
|
||||
* costs one stub here, not one per double.
|
||||
*/
|
||||
class NetworkOPsStub : public NetworkOPs
|
||||
{
|
||||
public:
|
||||
NetworkOPsStub() = default;
|
||||
~NetworkOPsStub() override = default;
|
||||
|
||||
void
|
||||
stop() override
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] OperatingMode
|
||||
getOperatingMode() const override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string
|
||||
strOperatingMode(OperatingMode const, bool const) const override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string
|
||||
strOperatingMode(bool const) const override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
submitTransaction(std::shared_ptr<STTx const> const&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
processTransaction(std::shared_ptr<Transaction>&, bool, bool, FailHard) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
processTransactionSet(CanonicalTXSet const&) override
|
||||
{
|
||||
}
|
||||
|
||||
json::Value
|
||||
getOwnerInfo(std::shared_ptr<ReadView const>, AccountID const&) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
getBookPage(
|
||||
std::shared_ptr<ReadView const>&,
|
||||
Book const&,
|
||||
AccountID const&,
|
||||
bool const,
|
||||
unsigned int,
|
||||
json::Value const&,
|
||||
json::Value&) override
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
processTrustedProposal(RCLCxPeerPos) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
recvValidation(std::shared_ptr<STValidation> const&, std::string const&) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
mapComplete(std::shared_ptr<SHAMap> const&, bool) override
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
beginConsensus(UInt256 const&, std::unique_ptr<std::stringstream> const&) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
endConsensus(std::unique_ptr<std::stringstream> const&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
setStandAlone() override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
setStateTimer() override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
setNeedNetworkLedger() override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
clearNeedNetworkLedger() override
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
isNeedNetworkLedger() override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
isFull() override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
setMode(OperatingMode) override
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
isBlocked() override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
isAmendmentBlocked() override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
setAmendmentBlocked() override
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
isAmendmentWarned() override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
setAmendmentWarned() override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
clearAmendmentWarned() override
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
isUNLBlocked() override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
setUNLBlocked() override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
clearUNLBlocked() override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
consensusViewChange() override
|
||||
{
|
||||
}
|
||||
|
||||
json::Value
|
||||
getConsensusInfo() override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
json::Value
|
||||
getServerInfo(bool, bool, bool) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
clearLedgerFetch() override
|
||||
{
|
||||
}
|
||||
|
||||
json::Value
|
||||
getLedgerFetchInfo() override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
acceptLedger(std::optional<std::chrono::milliseconds>) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
reportFeeChange() override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
updateLocalTx(ReadView const&) override
|
||||
{
|
||||
}
|
||||
|
||||
std::size_t
|
||||
getLocalTxCount() override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
pubLedger(std::shared_ptr<ReadView const> const&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
pubProposedTransaction(
|
||||
std::shared_ptr<ReadView const> const&,
|
||||
std::shared_ptr<STTx const> const&,
|
||||
TER) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
pubValidation(std::shared_ptr<STValidation> const&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
stateAccounting(json::Value&) override
|
||||
{
|
||||
}
|
||||
|
||||
std::size_t
|
||||
getBookSubscribersCount() override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
subAccount(InfoSub::Ref, HashSet<AccountID> const&, bool) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
unsubAccount(InfoSub::Ref, HashSet<AccountID> const&, bool) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
unsubAccountInternal(std::uint64_t, HashSet<AccountID> const&, bool) override
|
||||
{
|
||||
}
|
||||
|
||||
ErrorCodeI
|
||||
subAccountHistory(InfoSub::Ref, AccountID const&) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
unsubAccountHistory(InfoSub::Ref, AccountID const&, bool) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
unsubAccountHistoryInternal(std::uint64_t, AccountID const&, bool) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
unsubMPTInternal(std::uint64_t, MPTID const&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
scheduleAccountCleanup(
|
||||
std::uint64_t,
|
||||
HashSet<AccountID>,
|
||||
HashSet<AccountID>,
|
||||
HashSet<AccountID>) override
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
subLedger(InfoSub::Ref, json::Value&) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
unsubLedger(std::uint64_t) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
subBookChanges(InfoSub::Ref) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
unsubBookChanges(std::uint64_t) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
subManifests(InfoSub::Ref) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
unsubManifests(std::uint64_t) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
pubManifest(Manifest const&) override
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
subServer(InfoSub::Ref, json::Value&, bool) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
unsubServer(std::uint64_t) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
subBook(InfoSub::Ref, Book const&) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
unsubBook(InfoSub::Ref, Book const&) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
unsubBookInternal(std::uint64_t, Book const&) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
subTransactions(InfoSub::Ref) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
unsubTransactions(std::uint64_t) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
subRTTransactions(InfoSub::Ref) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
unsubRTTransactions(std::uint64_t) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
subValidations(InfoSub::Ref) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
unsubValidations(std::uint64_t) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
subPeerStatus(InfoSub::Ref) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
unsubPeerStatus(std::uint64_t) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
pubPeerStatus(std::function<json::Value()> const&) override
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
subConsensus(InfoSub::Ref) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
unsubConsensus(std::uint64_t) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
subMPT(InfoSub::Ref, HashSet<MPTID> const&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
unsubMPT(InfoSub::Ref, HashSet<MPTID> const&) override
|
||||
{
|
||||
}
|
||||
|
||||
InfoSub::pointer
|
||||
findRpcSub(std::string const&) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
InfoSub::pointer
|
||||
addRpcSub(std::string const&, InfoSub::Ref) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
tryRemoveRpcSub(std::string const&) override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] beast::Journal const&
|
||||
journal() const override
|
||||
{
|
||||
return j_;
|
||||
}
|
||||
|
||||
private:
|
||||
beast::Journal j_{beast::Journal::getNullSink()};
|
||||
};
|
||||
|
||||
} // namespace xrpl::test
|
||||
@@ -16,10 +16,12 @@
|
||||
#include <xrpl/core/ServiceRegistry.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/ApiVersion.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Book.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
#include <xrpl/protocol/JsonRpc.h>
|
||||
#include <xrpl/protocol/PathAsset.h>
|
||||
#include <xrpl/protocol/Quality.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
@@ -363,6 +365,35 @@ getAccountLines(Env& env, AccountID const& acctId, IOU... ious)
|
||||
[[nodiscard]] bool
|
||||
checkArraySize(json::Value const& val, unsigned int size);
|
||||
|
||||
/**
|
||||
* Reports whether @p reply carries the version 2 envelope: `jsonrpc` equal to
|
||||
* rpc::kJsonRpcVersion and `ripplerpc` equal to rpc::kRippleRpcVersion2, both
|
||||
* present.
|
||||
*
|
||||
* @param reply The reply to inspect.
|
||||
* @return True when both members are present with those values.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
inline bool
|
||||
hasEnvelope2(json::Value const& reply)
|
||||
{
|
||||
return reply.isMember(jss::jsonrpc) && reply[jss::jsonrpc] == rpc::kJsonRpcVersion &&
|
||||
reply.isMember(jss::ripplerpc) && reply[jss::ripplerpc] == rpc::kRippleRpcVersion2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the version 2 envelope on @p request: `jsonrpc` to rpc::kJsonRpcVersion
|
||||
* and `ripplerpc` to rpc::kRippleRpcVersion2.
|
||||
*
|
||||
* @param request The request to stamp.
|
||||
*/
|
||||
inline void
|
||||
setEnvelope2(json::Value& request)
|
||||
{
|
||||
request[jss::jsonrpc] = rpc::kJsonRpcVersion;
|
||||
request[jss::ripplerpc] = rpc::kRippleRpcVersion2;
|
||||
}
|
||||
|
||||
// Helper function that returns the owner count on an account.
|
||||
std::uint32_t
|
||||
ownerCount(test::jtx::Env const& env, test::jtx::Account const& account);
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <xrpl/json/json_reader.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/json/to_string.h>
|
||||
#include <xrpl/protocol/ApiVersion.h>
|
||||
#include <xrpl/protocol/JsonRpc.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/server/Port.h>
|
||||
|
||||
@@ -163,8 +165,8 @@ public:
|
||||
jr[jss::method] = cmd;
|
||||
if (rpcVersion_ == 2)
|
||||
{
|
||||
jr[jss::jsonrpc] = "2.0";
|
||||
jr[jss::ripplerpc] = "2.0";
|
||||
jr[jss::jsonrpc] = rpc::kJsonRpcVersion;
|
||||
jr[jss::ripplerpc] = rpc::kRippleRpcVersion2;
|
||||
jr[jss::id] = 5;
|
||||
}
|
||||
if (params)
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <xrpl/json/json_reader.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/json/to_string.h>
|
||||
#include <xrpl/protocol/ApiVersion.h>
|
||||
#include <xrpl/protocol/JsonRpc.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/server/Port.h>
|
||||
|
||||
@@ -207,8 +209,8 @@ public:
|
||||
if (rpcVersion_ == 2)
|
||||
{
|
||||
jp[jss::method] = cmd;
|
||||
jp[jss::jsonrpc] = "2.0";
|
||||
jp[jss::ripplerpc] = "2.0";
|
||||
jp[jss::jsonrpc] = rpc::kJsonRpcVersion;
|
||||
jp[jss::ripplerpc] = rpc::kRippleRpcVersion2;
|
||||
jp[jss::id] = 5;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
#include <test/jtx/Account.h>
|
||||
#include <test/jtx/Env.h>
|
||||
#include <test/jtx/TestHelpers.h>
|
||||
#include <test/jtx/amount.h>
|
||||
#include <test/jtx/flags.h>
|
||||
#include <test/jtx/multisign.h>
|
||||
@@ -426,8 +427,7 @@ public:
|
||||
BEAST_EXPECT(
|
||||
info.isMember(jss::result) && info[jss::result].isMember(jss::account_data));
|
||||
BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(jss::signer_lists));
|
||||
BEAST_EXPECT(info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(info));
|
||||
BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 5);
|
||||
}
|
||||
{
|
||||
@@ -440,8 +440,7 @@ public:
|
||||
auto const& signerLists = data[jss::signer_lists];
|
||||
BEAST_EXPECT(signerLists.isArray());
|
||||
BEAST_EXPECT(signerLists.size() == 0);
|
||||
BEAST_EXPECT(info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(info));
|
||||
BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 6);
|
||||
}
|
||||
{
|
||||
@@ -451,8 +450,7 @@ public:
|
||||
info[0u].isMember(jss::result) &&
|
||||
info[0u][jss::result].isMember(jss::account_data));
|
||||
BEAST_EXPECT(!info[0u][jss::result][jss::account_data].isMember(jss::signer_lists));
|
||||
BEAST_EXPECT(info[0u].isMember(jss::jsonrpc) && info[0u][jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(info[0u].isMember(jss::ripplerpc) && info[0u][jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(info[0u]));
|
||||
BEAST_EXPECT(info[0u].isMember(jss::id) && info[0u][jss::id] == 5);
|
||||
|
||||
BEAST_EXPECT(
|
||||
@@ -463,8 +461,7 @@ public:
|
||||
auto const& signerLists = data[jss::signer_lists];
|
||||
BEAST_EXPECT(signerLists.isArray());
|
||||
BEAST_EXPECT(signerLists.size() == 0);
|
||||
BEAST_EXPECT(info[1u].isMember(jss::jsonrpc) && info[1u][jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(info[1u].isMember(jss::ripplerpc) && info[1u][jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(info[1u]));
|
||||
BEAST_EXPECT(info[1u].isMember(jss::id) && info[1u][jss::id] == 6);
|
||||
}
|
||||
|
||||
@@ -479,8 +476,7 @@ public:
|
||||
BEAST_EXPECT(
|
||||
info.isMember(jss::result) && info[jss::result].isMember(jss::account_data));
|
||||
BEAST_EXPECT(!info[jss::result][jss::account_data].isMember(jss::signer_lists));
|
||||
BEAST_EXPECT(info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(info));
|
||||
BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 5);
|
||||
}
|
||||
{
|
||||
@@ -500,8 +496,7 @@ public:
|
||||
BEAST_EXPECT(signerEntries.size() == 1);
|
||||
auto const& entry0 = signerEntries[0u][sfSignerEntry.jsonName];
|
||||
BEAST_EXPECT(entry0[sfSignerWeight.jsonName] == 3);
|
||||
BEAST_EXPECT(info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(info));
|
||||
BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 6);
|
||||
}
|
||||
|
||||
@@ -550,8 +545,7 @@ public:
|
||||
BEAST_EXPECT(entry.isMember(sfAccount.jsonName));
|
||||
BEAST_EXPECT(entry[sfSignerWeight.jsonName] == 1);
|
||||
}
|
||||
BEAST_EXPECT(info.isMember(jss::jsonrpc) && info[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(info.isMember(jss::ripplerpc) && info[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(info));
|
||||
BEAST_EXPECT(info.isMember(jss::id) && info[jss::id] == 6);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -915,18 +915,15 @@ public:
|
||||
// account_lines with mal-formed json2 (missing id field).
|
||||
json::Value request;
|
||||
request[jss::method] = "account_lines";
|
||||
request[jss::jsonrpc] = "2.0";
|
||||
request[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(request);
|
||||
auto const lines = env.rpc("json2", to_string(request));
|
||||
BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(lines));
|
||||
}
|
||||
{
|
||||
// account_lines with no account.
|
||||
json::Value request;
|
||||
request[jss::method] = "account_lines";
|
||||
request[jss::jsonrpc] = "2.0";
|
||||
request[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(request);
|
||||
request[jss::id] = 5;
|
||||
auto const lines = env.rpc("json2", to_string(request));
|
||||
BEAST_EXPECT(lines[jss::error][jss::error] == "invalidParams");
|
||||
@@ -934,8 +931,7 @@ public:
|
||||
BEAST_EXPECT(
|
||||
lines[jss::error][jss::message] ==
|
||||
rpc::missingFieldError(jss::account)[jss::error_message]);
|
||||
BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(lines));
|
||||
BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
|
||||
}
|
||||
{
|
||||
@@ -944,8 +940,7 @@ public:
|
||||
params[jss::account] = "n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj";
|
||||
json::Value request;
|
||||
request[jss::method] = "account_lines";
|
||||
request[jss::jsonrpc] = "2.0";
|
||||
request[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(request);
|
||||
request[jss::id] = 5;
|
||||
request[jss::params] = params;
|
||||
auto const lines = env.rpc("json2", to_string(request));
|
||||
@@ -954,8 +949,7 @@ public:
|
||||
BEAST_EXPECT(
|
||||
lines[jss::error][jss::message] ==
|
||||
rpc::makeError(RpcActMalformed)[jss::error_message]);
|
||||
BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(lines));
|
||||
BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
|
||||
}
|
||||
Account const alice{"alice"};
|
||||
@@ -965,8 +959,7 @@ public:
|
||||
params[jss::account] = alice.human();
|
||||
json::Value request;
|
||||
request[jss::method] = "account_lines";
|
||||
request[jss::jsonrpc] = "2.0";
|
||||
request[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(request);
|
||||
request[jss::id] = 5;
|
||||
request[jss::params] = params;
|
||||
auto const lines = env.rpc("json2", to_string(request));
|
||||
@@ -975,8 +968,7 @@ public:
|
||||
BEAST_EXPECT(
|
||||
lines[jss::error][jss::message] ==
|
||||
rpc::makeError(RpcActNotFound)[jss::error_message]);
|
||||
BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(lines));
|
||||
BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
|
||||
}
|
||||
env.fund(XRP(10000), alice);
|
||||
@@ -993,8 +985,7 @@ public:
|
||||
|
||||
json::Value request;
|
||||
request[jss::method] = "account_lines";
|
||||
request[jss::jsonrpc] = "2.0";
|
||||
request[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(request);
|
||||
request[jss::id] = 5;
|
||||
request[jss::params] = params;
|
||||
|
||||
@@ -1002,8 +993,7 @@ public:
|
||||
BEAST_EXPECT(lines[jss::error][jss::error] == "invalidParams");
|
||||
BEAST_EXPECT(lines[jss::error][jss::error_code] == RpcInvalidParams);
|
||||
BEAST_EXPECT(lines[jss::error][jss::message] == "Invalid field 'peer'.");
|
||||
BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(lines));
|
||||
BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
|
||||
};
|
||||
|
||||
@@ -1020,15 +1010,13 @@ public:
|
||||
params[jss::account] = alice.human();
|
||||
json::Value request;
|
||||
request[jss::method] = "account_lines";
|
||||
request[jss::jsonrpc] = "2.0";
|
||||
request[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(request);
|
||||
request[jss::id] = 5;
|
||||
request[jss::params] = params;
|
||||
auto const lines = env.rpc("json2", to_string(request));
|
||||
BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
|
||||
BEAST_EXPECT(lines[jss::result][jss::lines].size() == 0);
|
||||
BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(lines));
|
||||
BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
|
||||
}
|
||||
{
|
||||
@@ -1038,8 +1026,7 @@ public:
|
||||
params[jss::ledger_index] = "nonsense";
|
||||
json::Value request;
|
||||
request[jss::method] = "account_lines";
|
||||
request[jss::jsonrpc] = "2.0";
|
||||
request[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(request);
|
||||
request[jss::id] = 5;
|
||||
request[jss::params] = params;
|
||||
auto const lines = env.rpc("json2", to_string(request));
|
||||
@@ -1048,8 +1035,7 @@ public:
|
||||
BEAST_EXPECT(
|
||||
lines[jss::error][jss::message] ==
|
||||
"Invalid field 'ledger_index', not string or number.");
|
||||
BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(lines));
|
||||
BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
|
||||
}
|
||||
{
|
||||
@@ -1059,16 +1045,14 @@ public:
|
||||
params[jss::ledger_index] = 50000;
|
||||
json::Value request;
|
||||
request[jss::method] = "account_lines";
|
||||
request[jss::jsonrpc] = "2.0";
|
||||
request[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(request);
|
||||
request[jss::id] = 5;
|
||||
request[jss::params] = params;
|
||||
auto const lines = env.rpc("json2", to_string(request));
|
||||
BEAST_EXPECT(lines[jss::error][jss::error] == "lgrNotFound");
|
||||
BEAST_EXPECT(lines[jss::error][jss::error_code] == RpcLgrNotFound);
|
||||
BEAST_EXPECT(lines[jss::error][jss::message] == "ledgerNotFound");
|
||||
BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(lines));
|
||||
BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
|
||||
}
|
||||
// Create trust lines to share with alice.
|
||||
@@ -1121,44 +1105,38 @@ public:
|
||||
BEAST_EXPECT(ledger58Info.seq == 58);
|
||||
|
||||
// A re-usable test for historic ledgers.
|
||||
auto const testAccountLinesHistory = [this, &env](
|
||||
Account const& account,
|
||||
LedgerHeader const& info,
|
||||
int count) {
|
||||
// Get account_lines by ledger index.
|
||||
json::Value paramsSeq;
|
||||
paramsSeq[jss::account] = account.human();
|
||||
paramsSeq[jss::ledger_index] = info.seq;
|
||||
json::Value requestSeq;
|
||||
requestSeq[jss::method] = "account_lines";
|
||||
requestSeq[jss::jsonrpc] = "2.0";
|
||||
requestSeq[jss::ripplerpc] = "2.0";
|
||||
requestSeq[jss::id] = 5;
|
||||
requestSeq[jss::params] = paramsSeq;
|
||||
auto const linesSeq = env.rpc("json2", to_string(requestSeq));
|
||||
BEAST_EXPECT(linesSeq[jss::result][jss::lines].isArray());
|
||||
BEAST_EXPECT(linesSeq[jss::result][jss::lines].size() == count);
|
||||
BEAST_EXPECT(linesSeq.isMember(jss::jsonrpc) && linesSeq[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(linesSeq.isMember(jss::ripplerpc) && linesSeq[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(linesSeq.isMember(jss::id) && linesSeq[jss::id] == 5);
|
||||
auto const testAccountLinesHistory =
|
||||
[this, &env](Account const& account, LedgerHeader const& info, int count) {
|
||||
// Get account_lines by ledger index.
|
||||
json::Value paramsSeq;
|
||||
paramsSeq[jss::account] = account.human();
|
||||
paramsSeq[jss::ledger_index] = info.seq;
|
||||
json::Value requestSeq;
|
||||
requestSeq[jss::method] = "account_lines";
|
||||
setEnvelope2(requestSeq);
|
||||
requestSeq[jss::id] = 5;
|
||||
requestSeq[jss::params] = paramsSeq;
|
||||
auto const linesSeq = env.rpc("json2", to_string(requestSeq));
|
||||
BEAST_EXPECT(linesSeq[jss::result][jss::lines].isArray());
|
||||
BEAST_EXPECT(linesSeq[jss::result][jss::lines].size() == count);
|
||||
BEAST_EXPECT(hasEnvelope2(linesSeq));
|
||||
BEAST_EXPECT(linesSeq.isMember(jss::id) && linesSeq[jss::id] == 5);
|
||||
|
||||
// Get account_lines by ledger hash.
|
||||
json::Value paramsHash;
|
||||
paramsHash[jss::account] = account.human();
|
||||
paramsHash[jss::ledger_hash] = to_string(info.hash);
|
||||
json::Value requestHash;
|
||||
requestHash[jss::method] = "account_lines";
|
||||
requestHash[jss::jsonrpc] = "2.0";
|
||||
requestHash[jss::ripplerpc] = "2.0";
|
||||
requestHash[jss::id] = 5;
|
||||
requestHash[jss::params] = paramsHash;
|
||||
auto const linesHash = env.rpc("json2", to_string(requestHash));
|
||||
BEAST_EXPECT(linesHash[jss::result][jss::lines].isArray());
|
||||
BEAST_EXPECT(linesHash[jss::result][jss::lines].size() == count);
|
||||
BEAST_EXPECT(linesHash.isMember(jss::jsonrpc) && linesHash[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(linesHash.isMember(jss::ripplerpc) && linesHash[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(linesHash.isMember(jss::id) && linesHash[jss::id] == 5);
|
||||
};
|
||||
// Get account_lines by ledger hash.
|
||||
json::Value paramsHash;
|
||||
paramsHash[jss::account] = account.human();
|
||||
paramsHash[jss::ledger_hash] = to_string(info.hash);
|
||||
json::Value requestHash;
|
||||
requestHash[jss::method] = "account_lines";
|
||||
setEnvelope2(requestHash);
|
||||
requestHash[jss::id] = 5;
|
||||
requestHash[jss::params] = paramsHash;
|
||||
auto const linesHash = env.rpc("json2", to_string(requestHash));
|
||||
BEAST_EXPECT(linesHash[jss::result][jss::lines].isArray());
|
||||
BEAST_EXPECT(linesHash[jss::result][jss::lines].size() == count);
|
||||
BEAST_EXPECT(hasEnvelope2(linesHash));
|
||||
BEAST_EXPECT(linesHash.isMember(jss::id) && linesHash[jss::id] == 5);
|
||||
};
|
||||
|
||||
// Alice should have no trust lines in ledger 3.
|
||||
testAccountLinesHistory(alice, ledger3Info, 0);
|
||||
@@ -1178,8 +1156,7 @@ public:
|
||||
params[jss::ledger_index] = ledger58Info.seq;
|
||||
json::Value request;
|
||||
request[jss::method] = "account_lines";
|
||||
request[jss::jsonrpc] = "2.0";
|
||||
request[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(request);
|
||||
request[jss::id] = 5;
|
||||
request[jss::params] = params;
|
||||
auto const lines = env.rpc("json2", to_string(request));
|
||||
@@ -1189,8 +1166,7 @@ public:
|
||||
lines[jss::error][jss::message] ==
|
||||
"Exactly one of 'ledger_hash' or 'ledger_index' can be "
|
||||
"specified.");
|
||||
BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(lines));
|
||||
BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
|
||||
}
|
||||
{
|
||||
@@ -1199,15 +1175,13 @@ public:
|
||||
params[jss::account] = alice.human();
|
||||
json::Value request;
|
||||
request[jss::method] = "account_lines";
|
||||
request[jss::jsonrpc] = "2.0";
|
||||
request[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(request);
|
||||
request[jss::id] = 5;
|
||||
request[jss::params] = params;
|
||||
auto const lines = env.rpc("json2", to_string(request));
|
||||
BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
|
||||
BEAST_EXPECT(lines[jss::result][jss::lines].size() == 52);
|
||||
BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(lines));
|
||||
BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
|
||||
}
|
||||
{
|
||||
@@ -1217,15 +1191,13 @@ public:
|
||||
params[jss::peer] = gw1.human();
|
||||
json::Value request;
|
||||
request[jss::method] = "account_lines";
|
||||
request[jss::jsonrpc] = "2.0";
|
||||
request[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(request);
|
||||
request[jss::id] = 5;
|
||||
request[jss::params] = params;
|
||||
auto const lines = env.rpc("json2", to_string(request));
|
||||
BEAST_EXPECT(lines[jss::result][jss::lines].isArray());
|
||||
BEAST_EXPECT(lines[jss::result][jss::lines].size() == 26);
|
||||
BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(lines));
|
||||
BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
|
||||
}
|
||||
{
|
||||
@@ -1235,8 +1207,7 @@ public:
|
||||
params[jss::peer] = "n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj";
|
||||
json::Value request;
|
||||
request[jss::method] = "account_lines";
|
||||
request[jss::jsonrpc] = "2.0";
|
||||
request[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(request);
|
||||
request[jss::id] = 5;
|
||||
request[jss::params] = params;
|
||||
auto const lines = env.rpc("json2", to_string(request));
|
||||
@@ -1245,8 +1216,7 @@ public:
|
||||
BEAST_EXPECT(
|
||||
lines[jss::error][jss::message] ==
|
||||
rpc::makeError(RpcActMalformed)[jss::error_message]);
|
||||
BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(lines));
|
||||
BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
|
||||
}
|
||||
{
|
||||
@@ -1256,8 +1226,7 @@ public:
|
||||
params[jss::limit] = -1;
|
||||
json::Value request;
|
||||
request[jss::method] = "account_lines";
|
||||
request[jss::jsonrpc] = "2.0";
|
||||
request[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(request);
|
||||
request[jss::id] = 5;
|
||||
request[jss::params] = params;
|
||||
auto const lines = env.rpc("json2", to_string(request));
|
||||
@@ -1266,8 +1235,7 @@ public:
|
||||
BEAST_EXPECT(
|
||||
lines[jss::error][jss::message] ==
|
||||
rpc::expectedFieldMessage(jss::limit, "unsigned integer"));
|
||||
BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(lines));
|
||||
BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
|
||||
}
|
||||
{
|
||||
@@ -1277,15 +1245,13 @@ public:
|
||||
paramsA[jss::limit] = 1;
|
||||
json::Value requestA;
|
||||
requestA[jss::method] = "account_lines";
|
||||
requestA[jss::jsonrpc] = "2.0";
|
||||
requestA[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(requestA);
|
||||
requestA[jss::id] = 5;
|
||||
requestA[jss::params] = paramsA;
|
||||
auto const linesA = env.rpc("json2", to_string(requestA));
|
||||
BEAST_EXPECT(linesA[jss::result][jss::lines].isArray());
|
||||
BEAST_EXPECT(linesA[jss::result][jss::lines].size() == 1);
|
||||
BEAST_EXPECT(linesA.isMember(jss::jsonrpc) && linesA[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(linesA.isMember(jss::ripplerpc) && linesA[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(linesA));
|
||||
BEAST_EXPECT(linesA.isMember(jss::id) && linesA[jss::id] == 5);
|
||||
|
||||
// Pick up from where the marker left off. We should get 51.
|
||||
@@ -1295,15 +1261,13 @@ public:
|
||||
paramsB[jss::marker] = marker;
|
||||
json::Value requestB;
|
||||
requestB[jss::method] = "account_lines";
|
||||
requestB[jss::jsonrpc] = "2.0";
|
||||
requestB[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(requestB);
|
||||
requestB[jss::id] = 5;
|
||||
requestB[jss::params] = paramsB;
|
||||
auto const linesB = env.rpc("json2", to_string(requestB));
|
||||
BEAST_EXPECT(linesB[jss::result][jss::lines].isArray());
|
||||
BEAST_EXPECT(linesB[jss::result][jss::lines].size() == 51);
|
||||
BEAST_EXPECT(linesB.isMember(jss::jsonrpc) && linesB[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(linesB.isMember(jss::ripplerpc) && linesB[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(linesB));
|
||||
BEAST_EXPECT(linesB.isMember(jss::id) && linesB[jss::id] == 5);
|
||||
|
||||
// Go again from where the marker left off, but set a limit of 3.
|
||||
@@ -1313,15 +1277,13 @@ public:
|
||||
paramsC[jss::marker] = marker;
|
||||
json::Value requestC;
|
||||
requestC[jss::method] = "account_lines";
|
||||
requestC[jss::jsonrpc] = "2.0";
|
||||
requestC[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(requestC);
|
||||
requestC[jss::id] = 5;
|
||||
requestC[jss::params] = paramsC;
|
||||
auto const linesC = env.rpc("json2", to_string(requestC));
|
||||
BEAST_EXPECT(linesC[jss::result][jss::lines].isArray());
|
||||
BEAST_EXPECT(linesC[jss::result][jss::lines].size() == 3);
|
||||
BEAST_EXPECT(linesC.isMember(jss::jsonrpc) && linesC[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(linesC.isMember(jss::ripplerpc) && linesC[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(linesC));
|
||||
BEAST_EXPECT(linesC.isMember(jss::id) && linesC[jss::id] == 5);
|
||||
|
||||
// Mess with the marker so it becomes bad and check for the error.
|
||||
@@ -1331,8 +1293,7 @@ public:
|
||||
paramsD[jss::marker] = marker;
|
||||
json::Value requestD;
|
||||
requestD[jss::method] = "account_lines";
|
||||
requestD[jss::jsonrpc] = "2.0";
|
||||
requestD[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(requestD);
|
||||
requestD[jss::id] = 5;
|
||||
requestD[jss::params] = paramsD;
|
||||
auto const linesD = env.rpc("json2", to_string(requestD));
|
||||
@@ -1341,8 +1302,7 @@ public:
|
||||
BEAST_EXPECT(
|
||||
linesD[jss::error][jss::message] ==
|
||||
rpc::makeError(RpcInvalidParams)[jss::error_message]);
|
||||
BEAST_EXPECT(linesD.isMember(jss::jsonrpc) && linesD[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(linesD.isMember(jss::ripplerpc) && linesD[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(linesD));
|
||||
BEAST_EXPECT(linesD.isMember(jss::id) && linesD[jss::id] == 5);
|
||||
}
|
||||
{
|
||||
@@ -1352,8 +1312,7 @@ public:
|
||||
params[jss::marker] = true;
|
||||
json::Value request;
|
||||
request[jss::method] = "account_lines";
|
||||
request[jss::jsonrpc] = "2.0";
|
||||
request[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(request);
|
||||
request[jss::id] = 5;
|
||||
request[jss::params] = params;
|
||||
auto const lines = env.rpc("json2", to_string(request));
|
||||
@@ -1362,8 +1321,7 @@ public:
|
||||
BEAST_EXPECT(
|
||||
lines[jss::error][jss::message] ==
|
||||
rpc::expectedFieldMessage(jss::marker, "string"));
|
||||
BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(lines));
|
||||
BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
|
||||
}
|
||||
{
|
||||
@@ -1374,8 +1332,7 @@ public:
|
||||
params[jss::peer] = gw2.human();
|
||||
json::Value request;
|
||||
request[jss::method] = "account_lines";
|
||||
request[jss::jsonrpc] = "2.0";
|
||||
request[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(request);
|
||||
request[jss::id] = 5;
|
||||
request[jss::params] = params;
|
||||
auto const lines = env.rpc("json2", to_string(request));
|
||||
@@ -1384,8 +1341,7 @@ public:
|
||||
BEAST_EXPECT(line[jss::deep_freeze].asBool() == true);
|
||||
BEAST_EXPECT(line[jss::no_ripple].asBool() == true);
|
||||
BEAST_EXPECT(line[jss::peer_authorized].asBool() == true);
|
||||
BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(lines.isMember(jss::ripplerpc) && lines[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(lines));
|
||||
BEAST_EXPECT(lines.isMember(jss::id) && lines[jss::id] == 5);
|
||||
}
|
||||
{
|
||||
@@ -1396,8 +1352,7 @@ public:
|
||||
paramsA[jss::peer] = alice.human();
|
||||
json::Value requestA;
|
||||
requestA[jss::method] = "account_lines";
|
||||
requestA[jss::jsonrpc] = "2.0";
|
||||
requestA[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(requestA);
|
||||
requestA[jss::id] = 5;
|
||||
requestA[jss::params] = paramsA;
|
||||
auto const linesA = env.rpc("json2", to_string(requestA));
|
||||
@@ -1406,8 +1361,7 @@ public:
|
||||
BEAST_EXPECT(lineA[jss::deep_freeze_peer].asBool() == true);
|
||||
BEAST_EXPECT(lineA[jss::no_ripple_peer].asBool() == true);
|
||||
BEAST_EXPECT(lineA[jss::authorized].asBool() == true);
|
||||
BEAST_EXPECT(linesA.isMember(jss::jsonrpc) && linesA[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(linesA.isMember(jss::ripplerpc) && linesA[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(linesA));
|
||||
BEAST_EXPECT(linesA.isMember(jss::id) && linesA[jss::id] == 5);
|
||||
|
||||
// Continue from the returned marker to make sure that works.
|
||||
@@ -1420,16 +1374,14 @@ public:
|
||||
paramsB[jss::peer] = alice.human();
|
||||
json::Value requestB;
|
||||
requestB[jss::method] = "account_lines";
|
||||
requestB[jss::jsonrpc] = "2.0";
|
||||
requestB[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(requestB);
|
||||
requestB[jss::id] = 5;
|
||||
requestB[jss::params] = paramsB;
|
||||
auto const linesB = env.rpc("json2", to_string(requestB));
|
||||
BEAST_EXPECT(linesB[jss::result][jss::lines].isArray());
|
||||
BEAST_EXPECT(linesB[jss::result][jss::lines].size() == 25);
|
||||
BEAST_EXPECT(!linesB[jss::result].isMember(jss::marker));
|
||||
BEAST_EXPECT(linesB.isMember(jss::jsonrpc) && linesB[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(linesB.isMember(jss::ripplerpc) && linesB[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(linesB));
|
||||
BEAST_EXPECT(linesB.isMember(jss::id) && linesB[jss::id] == 5);
|
||||
}
|
||||
}
|
||||
@@ -1489,15 +1441,13 @@ public:
|
||||
linesBegParams[jss::limit] = 2;
|
||||
json::Value linesBegRequest;
|
||||
linesBegRequest[jss::method] = "account_lines";
|
||||
linesBegRequest[jss::jsonrpc] = "2.0";
|
||||
linesBegRequest[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(linesBegRequest);
|
||||
linesBegRequest[jss::id] = 5;
|
||||
linesBegRequest[jss::params] = linesBegParams;
|
||||
auto const linesBeg = env.rpc("json2", to_string(linesBegRequest));
|
||||
BEAST_EXPECT(linesBeg[jss::result][jss::lines][0u][jss::currency] == "USD");
|
||||
BEAST_EXPECT(linesBeg[jss::result].isMember(jss::marker));
|
||||
BEAST_EXPECT(linesBeg.isMember(jss::jsonrpc) && linesBeg[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(linesBeg.isMember(jss::ripplerpc) && linesBeg[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(linesBeg));
|
||||
BEAST_EXPECT(linesBeg.isMember(jss::id) && linesBeg[jss::id] == 5);
|
||||
|
||||
// alice pays 100 USD to cheri.
|
||||
@@ -1511,8 +1461,7 @@ public:
|
||||
linesEndParams[jss::marker] = linesBeg[jss::result][jss::marker];
|
||||
json::Value linesEndRequest;
|
||||
linesEndRequest[jss::method] = "account_lines";
|
||||
linesEndRequest[jss::jsonrpc] = "2.0";
|
||||
linesEndRequest[jss::ripplerpc] = "2.0";
|
||||
setEnvelope2(linesEndRequest);
|
||||
linesEndRequest[jss::id] = 5;
|
||||
linesEndRequest[jss::params] = linesEndParams;
|
||||
auto const linesEnd = env.rpc("json2", to_string(linesEndRequest));
|
||||
@@ -1521,8 +1470,7 @@ public:
|
||||
BEAST_EXPECT(
|
||||
linesEnd[jss::error][jss::message] ==
|
||||
rpc::makeError(RpcInvalidParams)[jss::error_message]);
|
||||
BEAST_EXPECT(linesEnd.isMember(jss::jsonrpc) && linesEnd[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(linesEnd.isMember(jss::ripplerpc) && linesEnd[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(linesEnd));
|
||||
BEAST_EXPECT(linesEnd.isMember(jss::id) && linesEnd[jss::id] == 5);
|
||||
}
|
||||
|
||||
|
||||
+21
-40
@@ -1,4 +1,5 @@
|
||||
#include <test/jtx/Env.h>
|
||||
#include <test/jtx/TestHelpers.h>
|
||||
#include <test/jtx/WSClient.h>
|
||||
#include <test/jtx/amount.h>
|
||||
#include <test/jtx/domain.h>
|
||||
@@ -92,8 +93,7 @@ public:
|
||||
auto jv = wsc->invoke("subscribe", books);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
if (!BEAST_EXPECT(jv[jss::status] == "success"))
|
||||
@@ -130,8 +130,7 @@ public:
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
}
|
||||
@@ -169,8 +168,7 @@ public:
|
||||
auto jv = wsc->invoke("subscribe", books);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
if (!BEAST_EXPECT(jv[jss::status] == "success"))
|
||||
@@ -213,8 +211,7 @@ public:
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
}
|
||||
@@ -246,8 +243,7 @@ public:
|
||||
auto jv = wsc->invoke("subscribe", books);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
if (!BEAST_EXPECT(jv[jss::status] == "success"))
|
||||
@@ -292,8 +288,7 @@ public:
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
}
|
||||
@@ -332,8 +327,7 @@ public:
|
||||
auto jv = wsc->invoke("subscribe", books);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
if (!BEAST_EXPECT(jv[jss::status] == "success"))
|
||||
@@ -390,8 +384,7 @@ public:
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
}
|
||||
@@ -432,8 +425,7 @@ public:
|
||||
auto jv = wsc->invoke("subscribe", books);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
if (!BEAST_EXPECT(jv[jss::status] == "success"))
|
||||
@@ -491,8 +483,7 @@ public:
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
}
|
||||
@@ -546,8 +537,7 @@ public:
|
||||
auto jv = wsc->invoke("subscribe", books);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
if (!BEAST_EXPECT(jv[jss::status] == "success"))
|
||||
@@ -617,8 +607,7 @@ public:
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
}
|
||||
@@ -661,8 +650,7 @@ public:
|
||||
auto jv = wsc->invoke("subscribe", books);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
if (!BEAST_EXPECT(jv[jss::status] == "success"))
|
||||
@@ -735,8 +723,7 @@ public:
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
}
|
||||
@@ -793,8 +780,7 @@ public:
|
||||
auto jv = wsc->invoke("subscribe", books);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
if (!BEAST_EXPECT(jv[jss::status] == "success"))
|
||||
@@ -891,8 +877,7 @@ public:
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
}
|
||||
@@ -925,8 +910,7 @@ public:
|
||||
auto jv = wsc->invoke("subscribe", books);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
if (!BEAST_EXPECT(jv[jss::status] == "success"))
|
||||
@@ -956,8 +940,7 @@ public:
|
||||
auto jv = wsc->invoke("book_offers", jvParams);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
auto jrr = jv[jss::result];
|
||||
@@ -1001,8 +984,7 @@ public:
|
||||
jv = wsc->invoke("book_offers", jvParams);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
jrr = jv[jss::result];
|
||||
@@ -1027,8 +1009,7 @@ public:
|
||||
jv = wsc->invoke("unsubscribe", books);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <test/jtx/Account.h>
|
||||
#include <test/jtx/Env.h>
|
||||
#include <test/jtx/TestHelpers.h>
|
||||
#include <test/jtx/WSClient.h>
|
||||
#include <test/jtx/amount.h>
|
||||
#include <test/jtx/balance.h>
|
||||
@@ -22,6 +23,7 @@
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace xrpl::test {
|
||||
@@ -254,8 +256,7 @@ class DeliveredAmount_test : public beast::unit_test::Suite
|
||||
auto jv = wsc->invoke("subscribe", stream);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::result][jss::ledger_index] == 3);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <test/jtx/Account.h>
|
||||
#include <test/jtx/Env.h>
|
||||
#include <test/jtx/TestHelpers.h>
|
||||
#include <test/jtx/WSClient.h>
|
||||
#include <test/jtx/amount.h>
|
||||
#include <test/jtx/escrow.h>
|
||||
@@ -86,8 +87,7 @@ public:
|
||||
expect(jv[jss::status] == "success");
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
expect(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
expect(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
expect(hasEnvelope2(jv));
|
||||
expect(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
|
||||
|
||||
@@ -348,12 +348,8 @@ class LedgerEntry_test : public beast::unit_test::Suite
|
||||
apiVersion, "json", "ledger_entry", to_string(correctRequest))[jss::result];
|
||||
if (apiVersion < 2u)
|
||||
{
|
||||
BEAST_EXPECTS(jrr[jss::status] == "error", std::to_string(location.line()));
|
||||
BEAST_EXPECTS(
|
||||
jrr[jss::error] == "unknownOption", std::to_string(location.line()));
|
||||
BEAST_EXPECTS(!jrr.isMember(jss::error_code), std::to_string(location.line()));
|
||||
BEAST_EXPECTS(
|
||||
jrr[jss::error_message].isNull(), std::to_string(location.line()));
|
||||
checkErrorValue(
|
||||
jrr, "unknownOption", RpcUnknownOption, "Unknown option.", location);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -575,10 +571,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
|
||||
|
||||
if (apiVersion < 2u)
|
||||
{
|
||||
BEAST_EXPECT(jrr[jss::status] == "error");
|
||||
BEAST_EXPECT(jrr[jss::error] == "unknownOption");
|
||||
BEAST_EXPECT(!jrr.isMember(jss::error_code));
|
||||
BEAST_EXPECT(jrr[jss::error_message].isNull());
|
||||
checkErrorValue(jrr, "unknownOption", RpcUnknownOption, "Unknown option.");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -0,0 +1,397 @@
|
||||
#include <test/jtx/Env.h>
|
||||
|
||||
#include <xrpld/rpc/detail/MaskSecrets.h>
|
||||
|
||||
#include <xrpl/beast/unit_test/suite.h>
|
||||
#include <xrpl/json/json_reader.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/json/to_string.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
class MaskSecrets_test : public beast::unit_test::Suite
|
||||
{
|
||||
static constexpr char const* kMasked = "<masked>";
|
||||
static constexpr char const* kSensitive = "sensitive";
|
||||
|
||||
public:
|
||||
/**
|
||||
* Every field in `kCredentialFields` is masked, at the top level.
|
||||
*/
|
||||
void
|
||||
testEveryCredentialField()
|
||||
{
|
||||
testcase("Every credential field is masked");
|
||||
|
||||
json::Value request(json::ValueType::Object);
|
||||
for (auto const field : rpc::kCredentialFields)
|
||||
request[std::string{field}] = kSensitive;
|
||||
|
||||
auto const masked = rpc::maskSecrets(request);
|
||||
for (auto const field : rpc::kCredentialFields)
|
||||
BEAST_EXPECTS(masked[std::string{field}] == kMasked, std::string{field});
|
||||
|
||||
// An empty list would let every assertion above pass while masking nothing.
|
||||
BEAST_EXPECT(!rpc::kCredentialFields.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* A field the list does not name is left as it was.
|
||||
*/
|
||||
void
|
||||
testNonCredentialsSurvive()
|
||||
{
|
||||
testcase("Fields that are not credentials are left alone");
|
||||
|
||||
json::Value request(json::ValueType::Object);
|
||||
request[jss::method] = "sign";
|
||||
request[jss::account] = "rSomeAccount";
|
||||
request[jss::secret] = kSensitive;
|
||||
|
||||
auto const masked = rpc::maskSecrets(request);
|
||||
BEAST_EXPECT(masked[jss::secret] == kMasked);
|
||||
BEAST_EXPECT(masked[jss::method] == "sign");
|
||||
BEAST_EXPECT(masked[jss::account] == "rSomeAccount");
|
||||
|
||||
// Masking replaces members rather than adding or removing them.
|
||||
BEAST_EXPECT(masked.size() == request.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* A member name is matched whole, not as a substring or case-insensitively.
|
||||
*/
|
||||
void
|
||||
testNamesAreMatchedExactly()
|
||||
{
|
||||
testcase("Only an exact field name is masked");
|
||||
|
||||
json::Value request(json::ValueType::Object);
|
||||
for (auto const* name : {"secrets", "Secret", "my_secret", "seedling", "sec", ""})
|
||||
request[name] = kSensitive;
|
||||
|
||||
auto const masked = rpc::maskSecrets(request);
|
||||
for (auto const* name : {"secrets", "Secret", "my_secret", "seedling", "sec", ""})
|
||||
BEAST_EXPECTS(masked[name] == kSensitive, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* A credential is masked wherever it sits, not only at the top level.
|
||||
*
|
||||
* The JSON-RPC transport nests a request's fields inside `params`, which is
|
||||
* where a `secret` arrives.
|
||||
*/
|
||||
void
|
||||
testNesting()
|
||||
{
|
||||
testcase("A nested credential is masked at any depth");
|
||||
|
||||
// Where the JSON-RPC transport carries a credential: inside `params`.
|
||||
{
|
||||
json::Value params(json::ValueType::Object);
|
||||
params[jss::secret] = kSensitive;
|
||||
params[jss::account] = "rSomeAccount";
|
||||
|
||||
json::Value request(json::ValueType::Object);
|
||||
request[jss::method] = "sign";
|
||||
request[jss::params] = json::ValueType::Array;
|
||||
request[jss::params][0u] = params;
|
||||
|
||||
auto const masked = rpc::maskSecrets(request);
|
||||
BEAST_EXPECT(masked[jss::params][0u][jss::secret] == kMasked);
|
||||
BEAST_EXPECT(masked[jss::params][0u][jss::account] == "rSomeAccount");
|
||||
BEAST_EXPECT(masked[jss::method] == "sign");
|
||||
}
|
||||
|
||||
// Where a batch carries one: inside an entry, itself inside `params`.
|
||||
{
|
||||
json::Value entry(json::ValueType::Object);
|
||||
entry[jss::id] = 2;
|
||||
entry[jss::seed] = kSensitive;
|
||||
|
||||
json::Value batch(json::ValueType::Object);
|
||||
batch[jss::method] = "batch";
|
||||
batch[jss::params] = json::ValueType::Array;
|
||||
batch[jss::params][0u] = entry;
|
||||
|
||||
auto const masked = rpc::maskSecrets(batch);
|
||||
BEAST_EXPECT(masked[jss::params][0u][jss::seed] == kMasked);
|
||||
BEAST_EXPECT(masked[jss::params][0u][jss::id] == 2);
|
||||
}
|
||||
|
||||
// A credential in an array element, which names no member of its own.
|
||||
{
|
||||
json::Value inner(json::ValueType::Object);
|
||||
inner[jss::passphrase] = kSensitive;
|
||||
|
||||
json::Value request(json::ValueType::Array);
|
||||
request[0u] = inner;
|
||||
|
||||
auto const masked = rpc::maskSecrets(request);
|
||||
BEAST_EXPECT(masked[0u][jss::passphrase] == kMasked);
|
||||
}
|
||||
|
||||
// Up to the parser's nesting limit, which is what bounds the recursion.
|
||||
{
|
||||
json::Value deep(json::ValueType::Object);
|
||||
deep[jss::secret] = kSensitive;
|
||||
for (unsigned i{0}; i < json::Reader::kNestLimit; ++i)
|
||||
{
|
||||
json::Value outer(json::ValueType::Object);
|
||||
outer[jss::params] = deep;
|
||||
deep = outer;
|
||||
}
|
||||
|
||||
auto const masked = rpc::maskSecrets(deep);
|
||||
auto const* level = &masked;
|
||||
for (unsigned i{0}; i < json::Reader::kNestLimit; ++i)
|
||||
level = &(*level)[jss::params];
|
||||
BEAST_EXPECT((*level)[jss::secret] == kMasked);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A credential's own value is replaced whole, whatever shape it has.
|
||||
*
|
||||
* An object or array under `secret` is not walked into: the whole value is
|
||||
* the credential.
|
||||
*/
|
||||
void
|
||||
testCredentialIsNotDescendedInto()
|
||||
{
|
||||
testcase("A credential is replaced whatever it holds");
|
||||
|
||||
json::Value nested(json::ValueType::Object);
|
||||
nested["inner"] = kSensitive;
|
||||
|
||||
json::Value request(json::ValueType::Object);
|
||||
request[jss::secret] = nested;
|
||||
request[jss::seed] = json::ValueType::Array;
|
||||
request[jss::seed][0u] = kSensitive;
|
||||
|
||||
auto const masked = rpc::maskSecrets(request);
|
||||
BEAST_EXPECT(masked[jss::secret] == kMasked);
|
||||
BEAST_EXPECT(masked[jss::seed] == kMasked);
|
||||
|
||||
BEAST_EXPECT(!to_string(masked).contains(kSensitive));
|
||||
}
|
||||
|
||||
/**
|
||||
* A credential that is not a string is masked too, the value being replaced
|
||||
* whole.
|
||||
*/
|
||||
void
|
||||
testNonStringCredentials()
|
||||
{
|
||||
testcase("A credential of any type is masked");
|
||||
|
||||
json::Value request(json::ValueType::Object);
|
||||
request["secret"] = 12345;
|
||||
request["seed"] = true;
|
||||
request["passphrase"] = 1.5;
|
||||
request["password"] = json::ValueType::Null;
|
||||
|
||||
auto const masked = rpc::maskSecrets(request);
|
||||
for (auto const* field : {"secret", "seed", "passphrase", "password"})
|
||||
BEAST_EXPECTS(masked[field] == kMasked, field);
|
||||
}
|
||||
|
||||
/**
|
||||
* A value with no members is returned unchanged, masking keying on member
|
||||
* names.
|
||||
*/
|
||||
void
|
||||
testValuesWithoutMembers()
|
||||
{
|
||||
testcase("A value that has no members is returned unchanged");
|
||||
|
||||
BEAST_EXPECT(rpc::maskSecrets(json::Value{}).isNull());
|
||||
BEAST_EXPECT(rpc::maskSecrets(json::Value{kSensitive}) == kSensitive);
|
||||
BEAST_EXPECT(rpc::maskSecrets(json::Value{42}) == 42);
|
||||
BEAST_EXPECT(rpc::maskSecrets(json::Value{json::ValueType::Object}).size() == 0);
|
||||
BEAST_EXPECT(rpc::maskSecrets(json::Value{json::ValueType::Array}).size() == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* The request the caller passed in is not modified.
|
||||
*
|
||||
* Every call site goes on to use the request it holds, so the mask copies.
|
||||
*/
|
||||
void
|
||||
testRequestIsNotModified()
|
||||
{
|
||||
testcase("The request passed in is left unchanged");
|
||||
|
||||
json::Value request(json::ValueType::Object);
|
||||
request[jss::secret] = kSensitive;
|
||||
request[jss::params] = json::ValueType::Array;
|
||||
request[jss::params][0u] = json::ValueType::Object;
|
||||
request[jss::params][0u][jss::seed] = kSensitive;
|
||||
|
||||
auto const before = to_string(request);
|
||||
auto const masked = rpc::maskSecrets(request);
|
||||
|
||||
BEAST_EXPECT(to_string(request) == before);
|
||||
BEAST_EXPECT(request[jss::secret] == kSensitive);
|
||||
BEAST_EXPECT(request[jss::params][0u][jss::seed] == kSensitive);
|
||||
BEAST_EXPECT(masked[jss::secret] == kMasked);
|
||||
}
|
||||
|
||||
/**
|
||||
* `hasSecret` reports a credential at any depth and nothing else.
|
||||
*
|
||||
* Every name on the list is reported at the top level, one nested where the
|
||||
* JSON-RPC transport puts it and one inside an array element are reported
|
||||
* too, and a value naming none, or having no members at all, is not.
|
||||
*/
|
||||
void
|
||||
testHasSecret()
|
||||
{
|
||||
testcase("A credential is detected at any depth");
|
||||
|
||||
for (auto const field : rpc::kCredentialFields)
|
||||
{
|
||||
json::Value request(json::ValueType::Object);
|
||||
request[std::string{field}] = kSensitive;
|
||||
BEAST_EXPECTS(rpc::hasSecret(request), std::string{field});
|
||||
}
|
||||
|
||||
// Inside `params`, where the JSON-RPC transport carries a credential.
|
||||
{
|
||||
json::Value request(json::ValueType::Object);
|
||||
request[jss::method] = "sign";
|
||||
request[jss::params] = json::ValueType::Array;
|
||||
request[jss::params][0u] = json::ValueType::Object;
|
||||
request[jss::params][0u][jss::account] = "rSomeAccount";
|
||||
request[jss::params][0u][jss::secret] = kSensitive;
|
||||
BEAST_EXPECT(rpc::hasSecret(request));
|
||||
}
|
||||
|
||||
// Inside an array element, which names no member of its own.
|
||||
{
|
||||
json::Value request(json::ValueType::Array);
|
||||
request[0u] = json::ValueType::Object;
|
||||
request[0u][jss::passphrase] = kSensitive;
|
||||
BEAST_EXPECT(rpc::hasSecret(request));
|
||||
}
|
||||
|
||||
// No credential at any depth, and a near miss is not one.
|
||||
{
|
||||
json::Value request(json::ValueType::Object);
|
||||
request[jss::method] = "account_info";
|
||||
request[jss::params] = json::ValueType::Array;
|
||||
request[jss::params][0u] = json::ValueType::Object;
|
||||
request[jss::params][0u][jss::account] = "rSomeAccount";
|
||||
request[jss::params][0u]["secrets"] = kSensitive;
|
||||
BEAST_EXPECT(!rpc::hasSecret(request));
|
||||
}
|
||||
|
||||
// A value with no members carries none.
|
||||
BEAST_EXPECT(!rpc::hasSecret(json::Value{}));
|
||||
BEAST_EXPECT(!rpc::hasSecret(json::Value{kSensitive}));
|
||||
BEAST_EXPECT(!rpc::hasSecret(json::Value{42}));
|
||||
BEAST_EXPECT(!rpc::hasSecret(json::Value{json::ValueType::Object}));
|
||||
BEAST_EXPECT(!rpc::hasSecret(json::Value{json::ValueType::Array}));
|
||||
}
|
||||
|
||||
/**
|
||||
* `loggable` masks a value that carries a credential, then truncates at
|
||||
* `kMaxLoggedChars`; one that carries none is rendered as it is.
|
||||
*
|
||||
* The mask has to survive the cap, so the credential is placed where a
|
||||
* sorted member order puts it first.
|
||||
*/
|
||||
void
|
||||
testLoggable()
|
||||
{
|
||||
testcase("A rendering for a log line is masked and capped");
|
||||
|
||||
// Sorts before the filler, so the mask falls inside the cap.
|
||||
json::Value request;
|
||||
request[jss::secret] = kSensitive;
|
||||
request["zfiller"] = std::string(2 * rpc::kMaxLoggedChars, 'z');
|
||||
|
||||
auto const rendered = rpc::loggable(request);
|
||||
|
||||
BEAST_EXPECT(rendered.size() == rpc::kMaxLoggedChars);
|
||||
BEAST_EXPECT(rendered.contains(kMasked));
|
||||
BEAST_EXPECT(!rendered.contains(kSensitive));
|
||||
|
||||
// A short request is not padded.
|
||||
json::Value small;
|
||||
small[jss::seed] = kSensitive;
|
||||
BEAST_EXPECT(rpc::loggable(small) == to_string(rpc::maskSecrets(small)));
|
||||
|
||||
// A value with no credential is the serialized value itself, cut at the cap.
|
||||
json::Value plain;
|
||||
plain[jss::account] = "rSomeAccount";
|
||||
plain["zfiller"] = std::string(2 * rpc::kMaxLoggedChars, 'z');
|
||||
BEAST_EXPECT(rpc::loggable(plain) == to_string(plain).substr(0, rpc::kMaxLoggedChars));
|
||||
BEAST_EXPECT(rpc::loggable(small[jss::seed]) == to_string(small[jss::seed]));
|
||||
}
|
||||
|
||||
/**
|
||||
* A keygen reply is rendered for the log with no key in it.
|
||||
*
|
||||
* Every field of each reply is checked, not only the names on the list, so
|
||||
* a field the list is missing fails here. Only the fields a client may read
|
||||
* in public are allowed through.
|
||||
*/
|
||||
void
|
||||
testKeygenRepliesAreMasked()
|
||||
{
|
||||
testcase("A keygen reply is logged with every key masked");
|
||||
|
||||
static constexpr std::array<std::string_view, 6> kPublicFields{
|
||||
"account_id",
|
||||
"key_type",
|
||||
"public_key",
|
||||
"public_key_hex",
|
||||
"status",
|
||||
"validation_public_key",
|
||||
};
|
||||
|
||||
jtx::Env env{*this};
|
||||
for (auto const command : {"wallet_propose", "validation_create"})
|
||||
{
|
||||
auto const reply = env.rpc(command);
|
||||
auto const& result = reply[jss::result];
|
||||
BEAST_EXPECT(result[jss::status] == "success");
|
||||
|
||||
auto const rendered = rpc::loggable(reply);
|
||||
for (auto const& name : result.getMemberNames())
|
||||
{
|
||||
if (std::ranges::find(kPublicFields, name) != kPublicFields.end())
|
||||
continue;
|
||||
auto const& value = result[name];
|
||||
BEAST_EXPECT(value.isString() && !value.asString().empty());
|
||||
BEAST_EXPECTS(!rendered.contains(value.asString()), command + (": " + name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testEveryCredentialField();
|
||||
testNonCredentialsSurvive();
|
||||
testNamesAreMatchedExactly();
|
||||
testNesting();
|
||||
testCredentialIsNotDescendedInto();
|
||||
testNonStringCredentials();
|
||||
testValuesWithoutMembers();
|
||||
testRequestIsNotModified();
|
||||
testHasSecret();
|
||||
testLoggable();
|
||||
testKeygenRepliesAreMasked();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(MaskSecrets, rpc, xrpl);
|
||||
|
||||
} // namespace xrpl::test
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <test/jtx/Env.h>
|
||||
#include <test/jtx/TestHelpers.h>
|
||||
#include <test/jtx/WSClient.h>
|
||||
#include <test/jtx/amount.h>
|
||||
#include <test/jtx/balance.h> // IWYU pragma: keep
|
||||
@@ -38,8 +39,7 @@ public:
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
}
|
||||
@@ -53,8 +53,7 @@ public:
|
||||
auto jv = wsc->invoke("submit", payment);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::result][jss::engine_result] == "tefMAX_LEDGER");
|
||||
@@ -65,8 +64,7 @@ public:
|
||||
jv = wsc->invoke("submit", payment);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::result][jss::engine_result] == "tefPAST_SEQ");
|
||||
@@ -76,8 +74,7 @@ public:
|
||||
jv = wsc->invoke("submit", payment);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::result][jss::engine_result] == "terPRE_SEQ");
|
||||
@@ -87,8 +84,7 @@ public:
|
||||
jv = wsc->invoke("submit", payment);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::result][jss::engine_result] == "tesSUCCESS");
|
||||
@@ -100,8 +96,7 @@ public:
|
||||
jv = wsc->invoke("ledger_accept");
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::result].isMember(jss::ledger_current_index));
|
||||
@@ -128,8 +123,7 @@ public:
|
||||
jv = wsc->invoke("unsubscribe", jv);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
@@ -164,8 +158,7 @@ public:
|
||||
jv = wsc->invoke("submit", jv);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::result][jss::engine_result] == "tesSUCCESS");
|
||||
@@ -187,8 +180,7 @@ public:
|
||||
jv = wsc->invoke("account_tx", jv);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
|
||||
@@ -218,8 +210,7 @@ public:
|
||||
jv = wsc->invoke("submit", jv);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::result][jss::engine_result] == "tesSUCCESS");
|
||||
@@ -228,8 +219,7 @@ public:
|
||||
jv = wsc->invoke("ledger_accept");
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::result].isMember(jss::ledger_current_index));
|
||||
@@ -247,8 +237,7 @@ public:
|
||||
jv = wsc->invoke("subscribe", jv);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
@@ -260,8 +249,7 @@ public:
|
||||
auto jv = wsc->invoke("ledger_accept");
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::result].isMember(jss::ledger_current_index));
|
||||
@@ -281,8 +269,7 @@ public:
|
||||
jv = wsc->invoke("unsubscribe", jv);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
@@ -300,8 +287,7 @@ public:
|
||||
jv = wsc->invoke("subscribe", jv);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
@@ -313,8 +299,7 @@ public:
|
||||
auto jv = wsc->invoke("ledger_accept");
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::result].isMember(jss::ledger_current_index));
|
||||
@@ -334,8 +319,7 @@ public:
|
||||
jv = wsc->invoke("unsubscribe", jv);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
@@ -352,8 +336,7 @@ public:
|
||||
jv = wsc->invoke("account_tx", jv);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
|
||||
@@ -383,8 +366,7 @@ public:
|
||||
jv = wsc->invoke("subscribe", jv);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
@@ -399,8 +381,7 @@ public:
|
||||
jv = wsc->invoke("submit", jv);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::result][jss::engine_result] == "tesSUCCESS");
|
||||
@@ -421,8 +402,7 @@ public:
|
||||
jv = wsc->invoke("unsubscribe", jv);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
|
||||
@@ -338,8 +338,8 @@ class Simulate_test : public beast::unit_test::Suite
|
||||
|
||||
auto const resp = env.rpc("json", "simulate", to_string(params));
|
||||
BEAST_EXPECT(resp[jss::result][jss::error] == "invalidTransaction");
|
||||
BEAST_EXPECT(!resp[jss::result].isMember(jss::error_code));
|
||||
BEAST_EXPECT(resp[jss::result][jss::error_message].isNull());
|
||||
BEAST_EXPECT(resp[jss::result][jss::error_code] == RpcInvalidTransaction);
|
||||
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Transaction is invalid.");
|
||||
BEAST_EXPECT(
|
||||
resp[jss::result][jss::error_exception] ==
|
||||
"Field 'Destination' is required but missing.");
|
||||
@@ -359,6 +359,21 @@ class Simulate_test : public beast::unit_test::Suite
|
||||
BEAST_EXPECT(resp[jss::result][jss::error_code] == RpcSrcActMalformed);
|
||||
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'tx.Account'.");
|
||||
}
|
||||
{
|
||||
// A non-string `Account`, which no earlier check rejects: the `tx_json` arm validates
|
||||
// only that it is an object, and the check above only that `Account` is present.
|
||||
json::Value params;
|
||||
json::Value txJson = json::ValueType::Object;
|
||||
txJson[jss::TransactionType] = jss::AccountSet;
|
||||
txJson[jss::Account] = 123;
|
||||
params[jss::tx_json] = txJson;
|
||||
|
||||
auto const resp = env.rpc("json", "simulate", to_string(params));
|
||||
BEAST_EXPECTS(
|
||||
resp[jss::result][jss::error] == "invalidParams",
|
||||
resp[jss::result][jss::error].toStyledString());
|
||||
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'tx.Account'.");
|
||||
}
|
||||
{
|
||||
// Account doesn't exist for Sequence autofill
|
||||
json::Value params;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <test/jtx/Env.h>
|
||||
#include <test/jtx/TestHelpers.h>
|
||||
#include <test/jtx/WSClient.h>
|
||||
#include <test/jtx/amount.h>
|
||||
#include <test/jtx/batch.h>
|
||||
@@ -85,8 +86,7 @@ public:
|
||||
auto jv = wsc->invoke("subscribe", stream);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
@@ -115,8 +115,7 @@ public:
|
||||
auto jv = wsc->invoke("unsubscribe", stream);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
@@ -151,8 +150,7 @@ public:
|
||||
auto jv = wsc->invoke("subscribe", stream);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::result][jss::ledger_index] == 2);
|
||||
@@ -186,8 +184,7 @@ public:
|
||||
auto jv = wsc->invoke("unsubscribe", stream);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
@@ -210,8 +207,7 @@ public:
|
||||
auto jv = wsc->invoke("subscribe", stream);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
@@ -268,8 +264,7 @@ public:
|
||||
auto jv = wsc->invoke("unsubscribe", stream);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
@@ -283,8 +278,7 @@ public:
|
||||
auto jv = wsc->invoke("subscribe", stream);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
@@ -316,8 +310,7 @@ public:
|
||||
auto jv = wsc->invoke("unsubscribe", stream);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
@@ -346,8 +339,7 @@ public:
|
||||
auto jv = wsc->invoke("subscribe", stream);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
@@ -392,8 +384,7 @@ public:
|
||||
auto jv = wsc->invoke("unsubscribe", stream);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
@@ -415,8 +406,7 @@ public:
|
||||
auto jv = wsc->invoke("subscribe", stream);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
@@ -426,8 +416,7 @@ public:
|
||||
auto jv = wsc->invoke("unsubscribe", stream);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
@@ -474,8 +463,7 @@ public:
|
||||
auto jv = wsc->invoke("subscribe", stream);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
@@ -572,8 +560,7 @@ public:
|
||||
auto jv = wsc->invoke("unsubscribe", stream);
|
||||
if (wsc->version() == 2)
|
||||
{
|
||||
BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
|
||||
BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == "2.0");
|
||||
BEAST_EXPECT(hasEnvelope2(jv));
|
||||
BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
|
||||
}
|
||||
BEAST_EXPECT(jv[jss::status] == "success");
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <memory>
|
||||
#include <source_location>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
@@ -25,6 +26,45 @@ namespace xrpl {
|
||||
|
||||
class TransactionEntry_test : public beast::unit_test::Suite
|
||||
{
|
||||
/**
|
||||
* Asserts the reply carries the whole error, not just the token.
|
||||
*
|
||||
* @param result The reply's payload.
|
||||
* @param token The `error` token expected.
|
||||
* @param code The `error_code` expected.
|
||||
* @param message The `error_message` expected.
|
||||
* @param location The caller, reported when an assertion fails.
|
||||
*/
|
||||
void
|
||||
checkCodedError(
|
||||
json::Value const& result,
|
||||
std::string const& token,
|
||||
ErrorCodeI code,
|
||||
std::string const& message,
|
||||
std::source_location const location = std::source_location::current())
|
||||
{
|
||||
auto const at = std::to_string(location.line());
|
||||
|
||||
BEAST_EXPECTS(result[jss::error] == token, at);
|
||||
BEAST_EXPECTS(result[jss::error_code] == code, at);
|
||||
BEAST_EXPECTS(result[jss::error_message] == message, at);
|
||||
BEAST_EXPECTS(result[jss::status] == "error", at);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wire values pinned as literals, so reassigning a code fails here.
|
||||
*/
|
||||
void
|
||||
testErrorCodeValues()
|
||||
{
|
||||
testcase("Error code values are stable");
|
||||
|
||||
BEAST_EXPECT(static_cast<int>(RpcFieldNotFoundTransaction) == 104);
|
||||
BEAST_EXPECT(static_cast<int>(RpcNotYetImplemented) == 105);
|
||||
BEAST_EXPECT(static_cast<int>(RpcTransactionNotFound) == 106);
|
||||
BEAST_EXPECT(static_cast<int>(RpcMalformedRequest) == 107);
|
||||
}
|
||||
|
||||
void
|
||||
testBadInput()
|
||||
{
|
||||
@@ -38,10 +78,12 @@ class TransactionEntry_test : public beast::unit_test::Suite
|
||||
{
|
||||
// no params
|
||||
auto const result = env.client().invoke("transaction_entry", {})[jss::result];
|
||||
BEAST_EXPECT(result[jss::status] == "error");
|
||||
BEAST_EXPECT(result[jss::error] == "fieldNotFoundTransaction");
|
||||
BEAST_EXPECT(!result.isMember(jss::error_code));
|
||||
BEAST_EXPECT(result[jss::error_message].isNull());
|
||||
// The message names the missing field rather than the table's default.
|
||||
checkCodedError(
|
||||
result,
|
||||
"fieldNotFoundTransaction",
|
||||
RpcFieldNotFoundTransaction,
|
||||
"Missing field 'tx_hash'.");
|
||||
}
|
||||
|
||||
{
|
||||
@@ -59,10 +101,8 @@ class TransactionEntry_test : public beast::unit_test::Suite
|
||||
params[jss::ledger] = "current";
|
||||
params[jss::tx_hash] = "DEADBEEF";
|
||||
auto const result = env.client().invoke("transaction_entry", params)[jss::result];
|
||||
BEAST_EXPECT(result[jss::status] == "error");
|
||||
BEAST_EXPECT(result[jss::error] == "notYetImplemented");
|
||||
BEAST_EXPECT(!result.isMember(jss::error_code));
|
||||
BEAST_EXPECT(result[jss::error_message].isNull());
|
||||
checkCodedError(
|
||||
result, "notYetImplemented", RpcNotYetImplemented, "Not yet implemented.");
|
||||
}
|
||||
|
||||
{
|
||||
@@ -71,10 +111,8 @@ class TransactionEntry_test : public beast::unit_test::Suite
|
||||
params[jss::tx_hash] =
|
||||
"E2FE8D4AF3FCC3944DDF6CD8CDDC5E3F0AD50863EF8919AFEF10CB6408CD4D05";
|
||||
auto const result = env.client().invoke("transaction_entry", params)[jss::result];
|
||||
BEAST_EXPECT(result[jss::status] == "error");
|
||||
BEAST_EXPECT(result[jss::error] == "notYetImplemented");
|
||||
BEAST_EXPECT(!result.isMember(jss::error_code));
|
||||
BEAST_EXPECT(result[jss::error_message].isNull());
|
||||
checkCodedError(
|
||||
result, "notYetImplemented", RpcNotYetImplemented, "Not yet implemented.");
|
||||
BEAST_EXPECT(result.isMember(jss::ledger_current_index));
|
||||
BEAST_EXPECT(!result.isMember(jss::ledger_hash));
|
||||
BEAST_EXPECT(result[jss::validated] == false);
|
||||
@@ -86,22 +124,19 @@ class TransactionEntry_test : public beast::unit_test::Suite
|
||||
params[jss::tx_hash] = "DEADBEEF";
|
||||
auto const result = env.client().invoke("transaction_entry", params)[jss::result];
|
||||
BEAST_EXPECT(!result[jss::ledger_hash].asString().empty());
|
||||
BEAST_EXPECT(result[jss::status] == "error");
|
||||
BEAST_EXPECT(result[jss::error] == "malformedRequest");
|
||||
BEAST_EXPECT(!result.isMember(jss::error_code));
|
||||
BEAST_EXPECT(result[jss::error_message].isNull());
|
||||
checkCodedError(
|
||||
result, "malformedRequest", RpcMalformedRequest, "Request is malformed.");
|
||||
}
|
||||
|
||||
// A `tx_hash` that is not a string is malformed, the same as one that is not hex.
|
||||
for (auto const type : {json::ValueType::Object, json::ValueType::Array})
|
||||
{
|
||||
json::Value params{json::ValueType::Object};
|
||||
params[jss::ledger] = "closed";
|
||||
params[jss::tx_hash] = json::Value{type};
|
||||
auto const result = env.client().invoke("transaction_entry", params)[jss::result];
|
||||
BEAST_EXPECT(result[jss::status] == "error");
|
||||
BEAST_EXPECT(result[jss::error] == "malformedRequest");
|
||||
BEAST_EXPECT(!result.isMember(jss::error_code));
|
||||
BEAST_EXPECT(result[jss::error_message].isNull());
|
||||
checkCodedError(
|
||||
result, "malformedRequest", RpcMalformedRequest, "Request is malformed.");
|
||||
}
|
||||
|
||||
std::string const txHash{
|
||||
@@ -176,10 +211,11 @@ class TransactionEntry_test : public beast::unit_test::Suite
|
||||
// Valid structure, but transaction not found.
|
||||
json::Value const result{env.rpc("transaction_entry", txHash, "closed")};
|
||||
BEAST_EXPECT(!result[jss::result][jss::ledger_hash].asString().empty());
|
||||
BEAST_EXPECT(result[jss::result][jss::status] == "error");
|
||||
BEAST_EXPECT(result[jss::result][jss::error] == "transactionNotFound");
|
||||
BEAST_EXPECT(!result[jss::result].isMember(jss::error_code));
|
||||
BEAST_EXPECT(result[jss::result][jss::error_message].isNull());
|
||||
checkCodedError(
|
||||
result[jss::result],
|
||||
"transactionNotFound",
|
||||
RpcTransactionNotFound,
|
||||
"Transaction not found.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,6 +443,7 @@ public:
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testErrorCodeValues();
|
||||
testBadInput();
|
||||
forAllApiVersions([this](unsigned apiVersion) { testRequest(apiVersion); });
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -3,20 +3,3 @@
|
||||
This directory contains unit tests for the project. The difference from existing `src/test` folder
|
||||
is that we switch to 3rd party testing framework (`gtest`). We intend to gradually move existing tests
|
||||
from our own framework to `gtest` and such tests will be moved to this new folder.
|
||||
|
||||
## Layout
|
||||
|
||||
`libxrpl/` has one directory per libxrpl module, and two that are not modules: `helpers/` for test
|
||||
infrastructure shared by all of them, and `csf/` for the consensus simulation framework. Each
|
||||
directory is compiled into its own object library, and all of them are linked into the single
|
||||
`xrpl_tests` binary. `xrpld/` has one directory per server subsystem, all compiled into the
|
||||
`xrpld_tests` binary.
|
||||
|
||||
A test includes a header from the test tree under its canonical path, `<tests/libxrpl/<dir>/...>` or
|
||||
`<tests/xrpld/<dir>/...>`, the same way libxrpl's private headers are included. Under `libxrpl/` the
|
||||
headers of a directory are only visible to that directory and to the directories that link its
|
||||
target, so a test that needs another directory's headers has to declare that dependency in
|
||||
`libxrpl/CMakeLists.txt`. The `helpers/` directory is the exception: every directory can include it
|
||||
without declaring anything. Under `xrpld/` the directories cannot be isolated the same way, because
|
||||
the server headers are not a library and the whole `src` tree is on the include path, so there the
|
||||
canonical path is a convention only.
|
||||
@@ -5,74 +5,23 @@ include(verify_headers)
|
||||
# Test requirements.
|
||||
find_package(GTest REQUIRED)
|
||||
|
||||
# A single gtest binary, xrpl_tests, built from one object library per source
|
||||
# directory below. Each directory's headers are reachable only through its own
|
||||
# target, as <tests/libxrpl/<dir>/...>, so a test that needs another directory's
|
||||
# headers has to link that directory's target: the dependencies between test
|
||||
# directories are declared in this file and nowhere else, the same way the
|
||||
# libxrpl modules declare theirs. The shared `helpers` directory is available
|
||||
# to every other directory without declaring it.
|
||||
#
|
||||
# The object libraries link their dependencies only to compile against them.
|
||||
# Their object files go into the binary as sources, so the binary links each
|
||||
# library exactly once; linking the object libraries themselves would repeat
|
||||
# every dependency on the link line, which the Apple linker rejects.
|
||||
add_executable(xrpl_tests main.cpp)
|
||||
# Single combined gtest binary built from the shared test helpers and all test
|
||||
# modules below.
|
||||
add_executable(
|
||||
xrpl_tests
|
||||
main.cpp
|
||||
helpers/Account.cpp
|
||||
helpers/TestSink.cpp
|
||||
helpers/TxTest.cpp
|
||||
)
|
||||
patch_nix_binary(xrpl_tests)
|
||||
set_target_properties(
|
||||
xrpl_tests
|
||||
PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
|
||||
)
|
||||
# Lets test sources include the shared helpers as <helpers/...>.
|
||||
target_include_directories(xrpl_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(xrpl_tests PRIVATE GTest::gtest GTest::gmock xrpl.libxrpl)
|
||||
if(rust)
|
||||
target_link_libraries(xrpl_tests PRIVATE rs_hello_world_cxxbridge)
|
||||
endif()
|
||||
|
||||
# Compiles ${CMAKE_CURRENT_SOURCE_DIR}/${name} into the object library
|
||||
# xrpl_tests.${name}, exposes its headers under their canonical path, verifies
|
||||
# them against that target, and adds the objects to xrpl_tests.
|
||||
function(xrpl_add_test_dir name)
|
||||
set(target xrpl_tests.${name})
|
||||
file(
|
||||
GLOB_RECURSE sources
|
||||
CONFIGURE_DEPENDS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${name}/*.cpp"
|
||||
)
|
||||
if(NOT rust)
|
||||
# Tests of the Rust interop include generated cxxbridge headers, which
|
||||
# do not exist without the crates, so keep them out of the build tree
|
||||
# entirely. They are named `Rust<something>.cpp`.
|
||||
list(FILTER sources EXCLUDE REGEX "/Rust[^/]*\\.cpp$")
|
||||
endif()
|
||||
add_library(${target} OBJECT ${sources})
|
||||
target_link_libraries(
|
||||
${target}
|
||||
PRIVATE GTest::gtest GTest::gmock xrpl.libxrpl
|
||||
)
|
||||
if(NOT name STREQUAL "helpers")
|
||||
target_link_libraries(${target} PRIVATE xrpl_tests.helpers)
|
||||
endif()
|
||||
isolate_headers(
|
||||
${target}
|
||||
"${CMAKE_SOURCE_DIR}/src"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${name}"
|
||||
PUBLIC
|
||||
)
|
||||
# The test headers are not built with add_module, so verify them against
|
||||
# their own target's compile environment.
|
||||
if(verify_headers)
|
||||
verify_target_headers(${target} "${CMAKE_CURRENT_SOURCE_DIR}/${name}")
|
||||
endif()
|
||||
target_sources(xrpl_tests PRIVATE $<TARGET_OBJECTS:${target}>)
|
||||
endfunction()
|
||||
|
||||
# The shared helpers first, since every other directory links them.
|
||||
xrpl_add_test_dir(helpers)
|
||||
|
||||
# The CSF (Consensus Simulation Framework), used by the consensus tests. The
|
||||
# consensus engine itself lives in libxrpl, so no xrpld sources or include paths
|
||||
# are needed here.
|
||||
xrpl_add_test_dir(csf)
|
||||
|
||||
# One source subdirectory per module. Network unit tests are currently not
|
||||
# supported on Windows.
|
||||
@@ -95,14 +44,49 @@ set(test_modules
|
||||
if(NOT WIN32)
|
||||
list(APPEND test_modules net)
|
||||
endif()
|
||||
if(rust)
|
||||
target_link_libraries(xrpl_tests PRIVATE rs_hello_world_cxxbridge)
|
||||
endif()
|
||||
|
||||
foreach(module IN LISTS test_modules)
|
||||
xrpl_add_test_dir(${module})
|
||||
# Append the module's sources (${module}/*.cpp and ${module}.cpp, if any).
|
||||
file(
|
||||
GLOB_RECURSE sources
|
||||
CONFIGURE_DEPENDS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${module}/*.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${module}.cpp"
|
||||
)
|
||||
if(NOT rust)
|
||||
# Tests of the Rust interop include generated cxxbridge headers, which
|
||||
# do not exist without the crates, so keep them out of the build tree
|
||||
# entirely. They are named `Rust<something>.cpp`.
|
||||
list(FILTER sources EXCLUDE REGEX "/Rust[^/]*\\.cpp$")
|
||||
endif()
|
||||
target_sources(xrpl_tests PRIVATE ${sources})
|
||||
|
||||
# Expose the module's private headers under their canonical include path.
|
||||
isolate_headers(
|
||||
xrpl_tests
|
||||
"${CMAKE_SOURCE_DIR}"
|
||||
"${CMAKE_SOURCE_DIR}/tests/${module}"
|
||||
PRIVATE
|
||||
)
|
||||
endforeach()
|
||||
|
||||
# Dependencies between test directories, beyond the shared helpers.
|
||||
target_link_libraries(xrpl_tests.consensus PRIVATE xrpl_tests.csf)
|
||||
if(rust)
|
||||
target_link_libraries(xrpl_tests.basics PRIVATE rs_hello_world_cxxbridge)
|
||||
# The consensus tests use the CSF (Consensus Simulation Framework) helpers, so
|
||||
# compile the CSF sources into the test binary. The consensus engine itself now
|
||||
# lives in libxrpl, so no xrpld sources or include paths are needed here.
|
||||
file(
|
||||
GLOB_RECURSE csf_sources
|
||||
CONFIGURE_DEPENDS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/csf/*.cpp"
|
||||
)
|
||||
target_sources(xrpl_tests PRIVATE ${csf_sources})
|
||||
|
||||
# The test helpers and per-module test headers are not built with add_module,
|
||||
# so verify them against the test binary's own compile environment.
|
||||
if(verify_headers)
|
||||
verify_target_headers(xrpl_tests "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
endif()
|
||||
|
||||
gtest_discover_tests(xrpl_tests DISCOVERY_TIMEOUT 60)
|
||||
@@ -1,5 +1,3 @@
|
||||
#include <tests/libxrpl/helpers/TestSink.h>
|
||||
|
||||
#include <xrpl/basics/TaggedCache.h>
|
||||
#include <xrpl/basics/TaggedCache.ipp> // IWYU pragma: keep
|
||||
#include <xrpl/basics/chrono.h>
|
||||
@@ -7,6 +5,7 @@
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <helpers/TestSink.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include <xrpl/basics/TaggedCache.h>
|
||||
|
||||
#include <tests/libxrpl/helpers/TestSink.h>
|
||||
|
||||
#include <xrpl/basics/IntrusivePointer.h>
|
||||
#include <xrpl/basics/IntrusiveRefCounts.h>
|
||||
#include <xrpl/basics/TaggedCache.ipp> // IWYU pragma: keep
|
||||
@@ -10,6 +8,7 @@
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <helpers/TestSink.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
#include <tests/libxrpl/csf/Peer.h>
|
||||
#include <tests/libxrpl/csf/PeerGroup.h>
|
||||
#include <tests/libxrpl/csf/Sim.h>
|
||||
#include <tests/libxrpl/csf/SimTime.h>
|
||||
#include <tests/libxrpl/csf/TrustGraph.h>
|
||||
#include <tests/libxrpl/csf/collectors.h>
|
||||
|
||||
#include <xrpl/consensus/ConsensusParms.h>
|
||||
|
||||
#include <csf/Peer.h>
|
||||
#include <csf/PeerGroup.h>
|
||||
#include <csf/Sim.h>
|
||||
#include <csf/SimTime.h>
|
||||
#include <csf/TrustGraph.h>
|
||||
#include <csf/collectors.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
@@ -1,17 +1,5 @@
|
||||
#include <xrpl/consensus/Consensus.h>
|
||||
|
||||
#include <tests/libxrpl/csf/Peer.h>
|
||||
#include <tests/libxrpl/csf/PeerGroup.h>
|
||||
#include <tests/libxrpl/csf/Sim.h>
|
||||
#include <tests/libxrpl/csf/SimTime.h>
|
||||
#include <tests/libxrpl/csf/Tx.h>
|
||||
#include <tests/libxrpl/csf/Validation.h>
|
||||
#include <tests/libxrpl/csf/collectors.h>
|
||||
#include <tests/libxrpl/csf/events.h>
|
||||
#include <tests/libxrpl/csf/random.h>
|
||||
#include <tests/libxrpl/csf/submitters.h>
|
||||
#include <tests/libxrpl/helpers/TestSink.h>
|
||||
|
||||
#include <xrpl/basics/UnorderedContainers.h>
|
||||
#include <xrpl/basics/chrono.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
@@ -20,7 +8,18 @@
|
||||
#include <xrpl/consensus/DisputedTx.h>
|
||||
#include <xrpl/ledger/LedgerTiming.h>
|
||||
|
||||
#include <csf/Peer.h>
|
||||
#include <csf/PeerGroup.h>
|
||||
#include <csf/Sim.h>
|
||||
#include <csf/SimTime.h>
|
||||
#include <csf/Tx.h>
|
||||
#include <csf/Validation.h>
|
||||
#include <csf/collectors.h>
|
||||
#include <csf/events.h>
|
||||
#include <csf/random.h>
|
||||
#include <csf/submitters.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <helpers/TestSink.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#include <tests/libxrpl/csf/PeerGroup.h>
|
||||
#include <tests/libxrpl/csf/Sim.h>
|
||||
#include <tests/libxrpl/csf/collectors.h>
|
||||
#include <tests/libxrpl/csf/random.h>
|
||||
#include <tests/libxrpl/csf/submitters.h>
|
||||
#include <tests/libxrpl/csf/timers.h>
|
||||
|
||||
#include <csf/PeerGroup.h>
|
||||
#include <csf/Sim.h>
|
||||
#include <csf/collectors.h>
|
||||
#include <csf/random.h>
|
||||
#include <csf/submitters.h>
|
||||
#include <csf/timers.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <xrpl/consensus/LedgerTrie.h>
|
||||
|
||||
#include <tests/libxrpl/csf/ledgers.h>
|
||||
|
||||
#include <csf/ledgers.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
#include <tests/libxrpl/csf/PeerGroup.h>
|
||||
#include <tests/libxrpl/csf/Sim.h>
|
||||
#include <tests/libxrpl/csf/collectors.h>
|
||||
#include <tests/libxrpl/csf/random.h>
|
||||
#include <tests/libxrpl/csf/submitters.h>
|
||||
#include <tests/libxrpl/csf/timers.h>
|
||||
|
||||
#include <xrpl/consensus/ConsensusParms.h>
|
||||
|
||||
#include <csf/PeerGroup.h>
|
||||
#include <csf/Sim.h>
|
||||
#include <csf/collectors.h>
|
||||
#include <csf/random.h>
|
||||
#include <csf/submitters.h>
|
||||
#include <csf/timers.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
#include <xrpl/consensus/Validations.h>
|
||||
|
||||
#include <tests/libxrpl/csf/Validation.h>
|
||||
#include <tests/libxrpl/csf/ledgers.h>
|
||||
#include <tests/libxrpl/helpers/TestSink.h>
|
||||
|
||||
#include <xrpl/basics/UnorderedContainers.h>
|
||||
#include <xrpl/basics/chrono.h>
|
||||
#include <xrpl/basics/tagged_integer.h>
|
||||
@@ -11,7 +7,10 @@
|
||||
#include <xrpl/beast/clock/manual_clock.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
|
||||
#include <csf/Validation.h>
|
||||
#include <csf/ledgers.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <helpers/TestSink.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <tests/libxrpl/csf/BasicNetwork.h>
|
||||
|
||||
#include <tests/libxrpl/csf/Scheduler.h>
|
||||
#include <csf/BasicNetwork.h>
|
||||
|
||||
#include <csf/Scheduler.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <tests/libxrpl/csf/Digraph.h>
|
||||
#include <tests/libxrpl/csf/Scheduler.h>
|
||||
#include <csf/Digraph.h>
|
||||
#include <csf/Scheduler.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <tests/libxrpl/csf/Proposal.h>
|
||||
#include <tests/libxrpl/csf/SimTime.h>
|
||||
#include <tests/libxrpl/csf/Tx.h>
|
||||
#include <tests/libxrpl/csf/Validation.h>
|
||||
#include <tests/libxrpl/csf/events.h>
|
||||
#include <tests/libxrpl/csf/ledgers.h>
|
||||
#include <csf/Proposal.h>
|
||||
#include <csf/SimTime.h>
|
||||
#include <csf/Tx.h>
|
||||
#include <csf/Validation.h>
|
||||
#include <csf/events.h>
|
||||
#include <csf/ledgers.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <tests/libxrpl/csf/Digraph.h>
|
||||
#include <csf/Digraph.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <tests/libxrpl/csf/Histogram.h>
|
||||
#include <csf/Histogram.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <tests/libxrpl/csf/BasicNetwork.h>
|
||||
#include <tests/libxrpl/csf/CollectorRef.h>
|
||||
#include <tests/libxrpl/csf/Proposal.h>
|
||||
#include <tests/libxrpl/csf/Scheduler.h>
|
||||
#include <tests/libxrpl/csf/SimTime.h>
|
||||
#include <tests/libxrpl/csf/TrustGraph.h>
|
||||
#include <tests/libxrpl/csf/Tx.h>
|
||||
#include <tests/libxrpl/csf/Validation.h>
|
||||
#include <tests/libxrpl/csf/events.h>
|
||||
#include <tests/libxrpl/csf/ledgers.h>
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/UnorderedContainers.h>
|
||||
#include <xrpl/basics/chrono.h>
|
||||
@@ -27,6 +16,17 @@
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <boost/container/flat_set.hpp>
|
||||
|
||||
#include <csf/BasicNetwork.h>
|
||||
#include <csf/CollectorRef.h>
|
||||
#include <csf/Proposal.h>
|
||||
#include <csf/Scheduler.h>
|
||||
#include <csf/SimTime.h>
|
||||
#include <csf/TrustGraph.h>
|
||||
#include <csf/Tx.h>
|
||||
#include <csf/Validation.h>
|
||||
#include <csf/events.h>
|
||||
#include <csf/ledgers.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <tests/libxrpl/csf/Peer.h>
|
||||
#include <tests/libxrpl/csf/SimTime.h>
|
||||
#include <tests/libxrpl/csf/Validation.h>
|
||||
#include <tests/libxrpl/csf/random.h>
|
||||
#include <csf/Peer.h>
|
||||
#include <csf/SimTime.h>
|
||||
#include <csf/Validation.h>
|
||||
#include <csf/random.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <tests/libxrpl/csf/Tx.h>
|
||||
#include <tests/libxrpl/csf/Validation.h>
|
||||
#include <tests/libxrpl/csf/ledgers.h>
|
||||
|
||||
#include <xrpl/consensus/ConsensusProposal.h>
|
||||
|
||||
#include <csf/Tx.h>
|
||||
#include <csf/Validation.h>
|
||||
#include <csf/ledgers.h>
|
||||
|
||||
namespace xrpl::test::csf {
|
||||
/**
|
||||
* Proposal is a position taken in the consensus process and is represented
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <tests/libxrpl/csf/Scheduler.h>
|
||||
#include <csf/Scheduler.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <tests/libxrpl/csf/BasicNetwork.h>
|
||||
#include <tests/libxrpl/csf/CollectorRef.h>
|
||||
#include <tests/libxrpl/csf/Peer.h>
|
||||
#include <tests/libxrpl/csf/PeerGroup.h>
|
||||
#include <tests/libxrpl/csf/Scheduler.h>
|
||||
#include <tests/libxrpl/csf/SimTime.h>
|
||||
#include <tests/libxrpl/csf/TrustGraph.h>
|
||||
#include <tests/libxrpl/csf/ledgers.h>
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
|
||||
#include <csf/BasicNetwork.h>
|
||||
#include <csf/CollectorRef.h>
|
||||
#include <csf/Peer.h>
|
||||
#include <csf/PeerGroup.h>
|
||||
#include <csf/Scheduler.h>
|
||||
#include <csf/SimTime.h>
|
||||
#include <csf/TrustGraph.h>
|
||||
#include <csf/ledgers.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <tests/libxrpl/csf/Digraph.h>
|
||||
|
||||
#include <boost/container/flat_set.hpp>
|
||||
|
||||
#include <csf/Digraph.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <tests/libxrpl/csf/ledgers.h>
|
||||
|
||||
#include <xrpl/basics/chrono.h>
|
||||
#include <xrpl/basics/tagged_integer.h>
|
||||
|
||||
#include <csf/ledgers.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <tuple>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <tests/libxrpl/csf/Histogram.h>
|
||||
#include <tests/libxrpl/csf/SimTime.h>
|
||||
#include <tests/libxrpl/csf/Tx.h>
|
||||
#include <tests/libxrpl/csf/Validation.h>
|
||||
#include <tests/libxrpl/csf/events.h>
|
||||
|
||||
#include <xrpl/basics/UnorderedContainers.h>
|
||||
|
||||
#include <csf/Histogram.h>
|
||||
#include <csf/SimTime.h>
|
||||
#include <csf/Tx.h>
|
||||
#include <csf/Validation.h>
|
||||
#include <csf/events.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <tests/libxrpl/csf/Tx.h>
|
||||
#include <tests/libxrpl/csf/Validation.h>
|
||||
#include <tests/libxrpl/csf/ledgers.h>
|
||||
#include <csf/Tx.h>
|
||||
#include <csf/Validation.h>
|
||||
#include <csf/ledgers.h>
|
||||
|
||||
namespace xrpl::test::csf {
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <tests/libxrpl/csf/Sim.h>
|
||||
#include <csf/Sim.h>
|
||||
|
||||
#include <tests/libxrpl/csf/PeerGroup.h>
|
||||
#include <tests/libxrpl/csf/SimTime.h>
|
||||
#include <csf/PeerGroup.h>
|
||||
#include <csf/SimTime.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include <tests/libxrpl/csf/ledgers.h>
|
||||
|
||||
#include <tests/libxrpl/csf/Tx.h>
|
||||
#include <csf/ledgers.h>
|
||||
|
||||
#include <xrpl/basics/chrono.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/ledger/LedgerTiming.h>
|
||||
|
||||
#include <csf/Tx.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <tests/libxrpl/csf/Tx.h>
|
||||
|
||||
#include <xrpl/basics/chrono.h>
|
||||
#include <xrpl/basics/tagged_integer.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
@@ -9,6 +7,8 @@
|
||||
|
||||
#include <boost/bimap/bimap.hpp>
|
||||
|
||||
#include <csf/Tx.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <tests/libxrpl/csf/Scheduler.h>
|
||||
#include <tests/libxrpl/csf/SimTime.h>
|
||||
#include <tests/libxrpl/csf/Tx.h>
|
||||
#include <csf/Scheduler.h>
|
||||
#include <csf/SimTime.h>
|
||||
#include <csf/Tx.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <tests/libxrpl/csf/Scheduler.h>
|
||||
#include <tests/libxrpl/csf/SimTime.h>
|
||||
#include <csf/Scheduler.h>
|
||||
#include <csf/SimTime.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <tests/libxrpl/helpers/Account.h>
|
||||
#include <helpers/Account.h>
|
||||
|
||||
#include <xrpl/protocol/KeyType.h>
|
||||
#include <xrpl/protocol/PublicKey.h>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <tests/libxrpl/helpers/Account.h>
|
||||
|
||||
#include <xrpl/basics/Number.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
@@ -9,6 +7,8 @@
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
|
||||
#include <helpers/Account.h>
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <tests/libxrpl/helpers/TestNodeFamily.h>
|
||||
#include <tests/libxrpl/helpers/TestSink.h>
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/chrono.h>
|
||||
@@ -15,6 +12,9 @@
|
||||
|
||||
#include <boost/asio/io_context.hpp>
|
||||
|
||||
#include <helpers/TestSink.h>
|
||||
#include <shamap/common.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <tests/libxrpl/helpers/TestSink.h>
|
||||
#include <helpers/TestSink.h>
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
#include <tests/libxrpl/helpers/TxTest.h>
|
||||
|
||||
#include <tests/libxrpl/helpers/Account.h>
|
||||
#include <tests/libxrpl/helpers/IOU.h>
|
||||
#include <helpers/TxTest.h>
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/chrono.h>
|
||||
@@ -25,6 +22,9 @@
|
||||
#include <xrpl/protocol_autogen/transactions/Payment.h>
|
||||
#include <xrpl/tx/apply.h>
|
||||
|
||||
#include <helpers/Account.h>
|
||||
#include <helpers/IOU.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <tests/libxrpl/helpers/Account.h>
|
||||
#include <tests/libxrpl/helpers/IOU.h>
|
||||
#include <tests/libxrpl/helpers/TestServiceRegistry.h>
|
||||
|
||||
#include <xrpl/basics/Number.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/chrono.h>
|
||||
@@ -27,6 +23,10 @@
|
||||
#include <xrpl/protocol_autogen/ledger_entries/AccountRoot.h>
|
||||
#include <xrpl/tx/applySteps.h>
|
||||
|
||||
#include <helpers/Account.h>
|
||||
#include <helpers/IOU.h>
|
||||
#include <helpers/TestServiceRegistry.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
|
||||
@@ -598,6 +598,91 @@ TEST(JsonValue, compare_strings)
|
||||
#pragma pop_macro("DO_COMPARE")
|
||||
}
|
||||
|
||||
TEST(JsonValue, construct_from_string_view)
|
||||
{
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
// Characters are copied with an explicit length, so a view need not be NUL-terminated.
|
||||
EXPECT_EQ(json::Value{"2.0"sv}.asString(), "2.0");
|
||||
EXPECT_EQ(json::Value{"2.0 and more"sv.substr(0, 3)}.asString(), "2.0");
|
||||
EXPECT_EQ(json::Value{""sv}.asString(), "");
|
||||
|
||||
// A default-constructed view has a null `data()` and yields an empty string value.
|
||||
std::string_view const empty;
|
||||
json::Value const fromEmpty{empty};
|
||||
EXPECT_TRUE(fromEmpty.isString());
|
||||
EXPECT_EQ(fromEmpty.asString(), "");
|
||||
EXPECT_TRUE(fromEmpty == ""sv);
|
||||
|
||||
// The view need not outlive the call.
|
||||
json::Value copied;
|
||||
{
|
||||
std::string const owner{"borrowed"};
|
||||
copied = json::Value{std::string_view{owner}};
|
||||
}
|
||||
EXPECT_EQ(copied.asString(), "borrowed");
|
||||
|
||||
// A reader of a string value stops at the first NUL, so a view carrying one reads back short.
|
||||
json::Value const embedded{"a\0b"sv};
|
||||
EXPECT_EQ(embedded.asString(), "a");
|
||||
EXPECT_TRUE(embedded != "a\0b"sv);
|
||||
EXPECT_TRUE(embedded == "a"sv);
|
||||
EXPECT_TRUE(embedded == json::Value{"a\0b"sv});
|
||||
}
|
||||
|
||||
TEST(JsonValue, compare_string_view)
|
||||
{
|
||||
// Comparing against a view builds no temporary Value.
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
EXPECT_TRUE(json::Value{"2.0"} == "2.0"sv);
|
||||
EXPECT_FALSE(json::Value{"2.0"} != "2.0"sv);
|
||||
EXPECT_TRUE(json::Value{"2.0"} != "2.00"sv);
|
||||
EXPECT_TRUE(json::Value{"2.0"} != ""sv);
|
||||
|
||||
// A view need not be NUL-terminated, and the comparison must not read past its end.
|
||||
EXPECT_TRUE(json::Value{"2.0"} == "2.0 and more"sv.substr(0, 3));
|
||||
|
||||
EXPECT_TRUE(json::Value{""} == ""sv);
|
||||
|
||||
// A string value holding a null pointer equals nothing, not even the empty view.
|
||||
EXPECT_TRUE(json::Value{json::ValueType::String} != ""sv);
|
||||
EXPECT_TRUE(json::Value{json::ValueType::String} != "2.0"sv);
|
||||
EXPECT_TRUE(json::Value{json::ValueType::String} != json::Value{""});
|
||||
|
||||
// Nothing that is not a string equals one. Null is what an absent member reads as.
|
||||
EXPECT_TRUE(json::Value{json::ValueType::Null} != ""sv);
|
||||
EXPECT_TRUE(json::Value{json::ValueType::Null} != "2.0"sv);
|
||||
EXPECT_TRUE(json::Value{2} != "2"sv);
|
||||
EXPECT_TRUE(json::Value{true} != "true"sv);
|
||||
EXPECT_TRUE(json::Value{json::ValueType::Object} != ""sv);
|
||||
|
||||
// Only a view reaches this overload; every other spelling compares through Value.
|
||||
static constexpr json::StaticString kVersion{"2.0"};
|
||||
EXPECT_TRUE(json::Value{"2.0"} == kVersion);
|
||||
EXPECT_TRUE(json::Value{"2.1"} != kVersion);
|
||||
EXPECT_TRUE(json::Value{} != kVersion);
|
||||
|
||||
EXPECT_TRUE(json::Value{"2.0"} == "2.0");
|
||||
EXPECT_TRUE(json::Value{"2.0"} != "2.1");
|
||||
EXPECT_TRUE(json::Value{} != "2.0");
|
||||
|
||||
EXPECT_TRUE(json::Value{"2.0"} == std::string{"2.0"});
|
||||
EXPECT_TRUE(json::Value{"2.0"} != std::string{"2.1"});
|
||||
EXPECT_TRUE(json::Value{json::ValueType::Null} != std::string{"2.0"});
|
||||
|
||||
// A literal `0` also converts to a view through `char const*`, so a plain overload would make
|
||||
// this comparison ambiguous. It must compare as a number: RPCCall.cpp rejects a
|
||||
// `transaction_entry` ledger index this way.
|
||||
EXPECT_TRUE(json::Value{0} == 0);
|
||||
EXPECT_TRUE(json::Value{4294967295u} != 0);
|
||||
EXPECT_TRUE(json::Value{""} != 0);
|
||||
EXPECT_TRUE(json::Value{2} != 0);
|
||||
|
||||
// A null and an Int are different types, so the comparison is false.
|
||||
EXPECT_TRUE(json::Value{} != 0);
|
||||
}
|
||||
|
||||
TEST(JsonValue, bool)
|
||||
{
|
||||
EXPECT_FALSE(json::Value());
|
||||
@@ -634,6 +719,35 @@ TEST(JsonValue, bad_json)
|
||||
EXPECT_TRUE(r.parse(s, j));
|
||||
}
|
||||
|
||||
TEST(JsonValue, reject_null_in_string)
|
||||
{
|
||||
// json::Value keeps a string only through its first NUL, so a NUL in the document would make
|
||||
// "3.0\u0000junk" read as "3.0". The reader refuses it, escaped or raw, in a value or a key.
|
||||
using namespace std::string_literals;
|
||||
for (auto const& doc : {
|
||||
R"JSON({"v": "3.0\u0000junk"})JSON"s,
|
||||
R"JSON({"v\u0000junk": 1})JSON"s,
|
||||
R"JSON({"v": "\u0000"})JSON"s,
|
||||
"{\"v\": \"3.0\0junk\"}"s,
|
||||
})
|
||||
{
|
||||
json::Value j;
|
||||
json::Reader r;
|
||||
EXPECT_FALSE(r.parse(doc, j)) << doc;
|
||||
|
||||
// The message names the condition, not the text around it.
|
||||
auto const message = r.getFormattedErrorMessages();
|
||||
EXPECT_TRUE(message.contains("Null character in string")) << message;
|
||||
EXPECT_FALSE(message.contains("junk")) << message;
|
||||
}
|
||||
|
||||
// Every other control character still decodes.
|
||||
json::Value j;
|
||||
json::Reader r;
|
||||
ASSERT_TRUE(r.parse(R"JSON({"v": "a\u0001b"})JSON", j));
|
||||
EXPECT_EQ(j["v"].asString(), "a\x01"s + "b");
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] std::optional<json::Value>
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
#include <xrpl/ledger/entries/AMMEntry.h>
|
||||
|
||||
#include <tests/libxrpl/helpers/IOU.h>
|
||||
#include <tests/libxrpl/ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <helpers/IOU.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||
|
||||
#include <tests/libxrpl/helpers/Account.h>
|
||||
#include <tests/libxrpl/ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <helpers/Account.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#include <xrpl/ledger/entries/AmendmentsEntry.h>
|
||||
|
||||
#include <tests/libxrpl/ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#include <xrpl/ledger/entries/CheckEntry.h>
|
||||
|
||||
#include <tests/libxrpl/ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
#include <xrpl/ledger/entries/CredentialEntry.h>
|
||||
|
||||
#include <tests/libxrpl/ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#include <xrpl/ledger/entries/DIDEntry.h>
|
||||
|
||||
#include <tests/libxrpl/ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#include <xrpl/ledger/entries/DelegateEntry.h>
|
||||
|
||||
#include <tests/libxrpl/ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
#include <xrpl/ledger/entries/DepositPreauthEntry.h>
|
||||
|
||||
#include <tests/libxrpl/ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#include <xrpl/ledger/entries/DirectoryNodeEntry.h>
|
||||
|
||||
#include <tests/libxrpl/ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <tests/libxrpl/helpers/Account.h>
|
||||
#include <tests/libxrpl/helpers/TxTest.h>
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ApplyViewImpl.h>
|
||||
@@ -11,6 +8,8 @@
|
||||
#include <xrpl/protocol/LedgerHeader.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <helpers/Account.h>
|
||||
#include <helpers/TxTest.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#include <xrpl/ledger/entries/EscrowEntry.h>
|
||||
|
||||
#include <tests/libxrpl/ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#include <tests/libxrpl/helpers/TestNodeFamily.h>
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/chrono.h>
|
||||
#include <xrpl/beast/hash/uhash.h>
|
||||
@@ -15,6 +13,7 @@
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <shamap/common.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#include <xrpl/ledger/entries/FeeSettingsEntry.h>
|
||||
|
||||
#include <tests/libxrpl/ledger/EntryTestHelpers.h>
|
||||
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ledger/EntryTestHelpers.h>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
|
||||
Loaded 100 of 262 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user