Compare commits

...

27 Commits

Author SHA1 Message Date
Mayukha Vadari
6558ce3d22 Merge remote-tracking branch 'upstream/develop' into copilot/add-augmented-submit-fields 2026-09-11 10:35:23 -04:00
Sergey Kuznetsov
9403736199 ci: Exclude Rust unit tests from code coverage (#8203) 2026-09-10 11:38:25 +00:00
Mayukha Vadari
4b2cd3637d Merge remote-tracking branch 'upstream/develop' into copilot/add-augmented-submit-fields 2026-09-04 10:45:14 -04:00
Mayukha Vadari
7f0190949a Merge remote-tracking branch 'upstream/develop' into copilot/add-augmented-submit-fields 2026-09-03 16:52:04 -04:00
Mayukha Vadari
73d2ed51c4 Merge branch 'develop' into copilot/add-augmented-submit-fields 2026-08-31 16:59:03 -04:00
Mayukha Vadari
5a76baabb3 Merge branch 'develop' into copilot/add-augmented-submit-fields 2026-08-17 22:02:17 -04:00
Mayukha Vadari
373952a62c Merge branch 'develop' into copilot/add-augmented-submit-fields 2026-08-12 11:07:38 -04:00
Ayaz Salikhov
739ef8639a build: Respect lld linker if it gets auto-selected (#8011) 2026-08-12 14:03:37 +00:00
Vito Tumas
dc8973053e test: Fix LoanBatch broker cover rates and schedule overflow (#7967) 2026-08-12 13:42:55 +00:00
Timur Yalymov
d06a03baa6 test: Verify private-vault DEX permissions survive domain loss (#7937) 2026-08-12 13:42:02 +00:00
Timur Yalymov
050dbc628f refactor: Drop dead associateAsset calls from loan delete paths (#7986)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-12 13:41:30 +00:00
Mayukha Vadari
261b5201e0 fix: use lowercase rpc namespace after rename 2026-08-11 15:02:12 -04:00
Mayukha Vadari
890b2cfa17 Merge branch 'develop' into copilot/add-augmented-submit-fields 2026-08-11 14:21:43 -04:00
Mayukha Vadari
f03f890511 Merge branch 'develop' into copilot/add-augmented-submit-fields 2026-08-10 14:53:17 -04:00
Mayukha Vadari
553a36ac6f Merge branch 'develop' into copilot/add-augmented-submit-fields 2026-07-27 15:39:37 -04:00
Mayukha Vadari
e6d849dd01 fix pre-commit 2026-07-27 15:39:18 -04:00
Mayukha Vadari
a1ac0a31de fix changelog 2026-07-21 18:41:28 -04:00
Mayukha Vadari
1368a1cdf1 fix clang-tidy 2026-07-21 18:40:38 -04:00
Mayukha Vadari
91724750fb fix build issues 2026-07-21 18:38:48 -04:00
Mayukha Vadari
8febef6777 Merge branch 'develop' into copilot/add-augmented-submit-fields 2026-07-21 17:59:01 -04:00
copilot-swe-agent[bot]
3bc338211a Merge develop and resolve conflicts
- Updated Json::Value to json::Value (lowercase namespace)
- Updated safe_cast to safeCast
- Updated constant naming (e.g., defaultAutoFillFeeMultiplier to kDefaultAutoFillFeeMultiplier)
- Merged testAugmentedFields with testFailHardValidation in Submit_test.cpp
- Updated namespace from xrpl to xrpl::test for test files
- Updated beast::unit_test::suite to beast::unit_test::Suite

Co-authored-by: mvadari <8029314+mvadari@users.noreply.github.com>
2026-05-15 17:50:26 +00:00
Mayukha Vadari
1b05dba80b fix pre-commit issues 2026-04-03 11:00:23 -04:00
Mayukha Vadari
3595ad0928 fix issues 2026-04-03 10:56:04 -04:00
copilot-swe-agent[bot]
0af23e1466 Extract helper function to avoid code duplication and update API-CHANGELOG
Co-authored-by: mvadari <8029314+mvadari@users.noreply.github.com>
2026-04-03 10:55:42 -04:00
copilot-swe-agent[bot]
cfcf1d30e2 Fix includes in Submit_test.cpp
Co-authored-by: mvadari <8029314+mvadari@users.noreply.github.com>
2026-04-03 10:54:51 -04:00
copilot-swe-agent[bot]
6f8618b2f2 Fix test to properly construct transaction JSON for sign-and-submit
Co-authored-by: mvadari <8029314+mvadari@users.noreply.github.com>
2026-04-03 10:54:51 -04:00
copilot-swe-agent[bot]
361f3469b8 Add augmented fields to sign-and-submit mode and create test
Co-authored-by: mvadari <8029314+mvadari@users.noreply.github.com>
2026-04-03 10:54:51 -04:00
21 changed files with 334 additions and 37 deletions

View File

@@ -1,5 +1,5 @@
{
"image_tag": "sha-473fe44",
"image_tag": "sha-060957e",
"configs": {
"ubuntu": [
{

View File

@@ -5,15 +5,13 @@ on:
branches:
- develop
paths:
- ".github/workflows/build-nix-images.yml"
- "flake.nix"
- "flake.lock"
- "rust-toolchain.toml"
- "nix/**"
- "!nix/docker/README.md"
- "!nix/devshell.nix"
- "!nix/check-tools/*.txt"
- "bin/check-tools.sh"
- "!nix/check-tools/**"
- "bin/default-loader-path.sh"
- "bin/install-sanitizer-libs.sh"
pull_request:
@@ -25,7 +23,7 @@ on:
- "nix/**"
- "!nix/docker/README.md"
- "!nix/devshell.nix"
- "!nix/check-tools/*.txt"
- "!nix/check-tools/**"
- "bin/check-tools.sh"
- "bin/default-loader-path.sh"
- "bin/install-sanitizer-libs.sh"

View File

@@ -34,7 +34,7 @@ permissions:
jobs:
audit:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-473fe44
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
permissions:
contents: read
# Needed to open an issue on scheduled failures.

View File

@@ -41,7 +41,7 @@ env:
jobs:
build:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-473fe44
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

View File

@@ -34,7 +34,7 @@ jobs:
needs: [determine-files]
if: ${{ needs.determine-files.outputs.cpp_changed_files != '' || needs.determine-files.outputs.need_full_run == 'true' }}
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-473fe44"
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-060957e"
permissions:
contents: read
issues: write

View File

@@ -1,8 +1,9 @@
# Clippy, coverage and documentation for the Rust crates in crates/. Each runs
# as an independent job on a GitHub-hosted runner, but inside the same container
# image used to build the crates in the C++/Corrosion path, so the toolchain
# (and therefore the lints, coverage instrumentation and the cargo cache) matches
# what production builds use.
# (and therefore the lints and the cargo cache) matches what production builds
# use. Coverage is the exception: it needs the nightly rustc that honours
# #[coverage(off)], which the image carries alongside the pinned stable.
#
# Rust unit tests are deliberately NOT run here. They run as part of the C++
# build (reusable-build-test-config.yml), which already compiles the crates on a
@@ -27,7 +28,7 @@ permissions:
jobs:
clippy:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-473fe44
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -40,11 +41,14 @@ jobs:
coverage:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-473fe44
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Use the nightly Rust toolchain
run: rust-nightly path >>"${GITHUB_PATH}"
- name: Use cargo artifacts cache
uses: ./.github/actions/cargo-cache
@@ -66,7 +70,7 @@ jobs:
doc:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-473fe44
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

View File

@@ -40,7 +40,7 @@ defaults:
jobs:
upload:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-473fe44
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
env:
REMOTE_NAME: ${{ inputs.remote_name }}
CONAN_LOGIN_USERNAME_XRPLF: ${{ secrets.remote_username }}

View File

@@ -70,6 +70,11 @@ repos:
language: system
types: [rust]
pass_filenames: false # rustfmt formats the whole workspace
- id: check-coverage-attrs
name: check Rust coverage attributes
entry: ./bin/pre-commit/check_rust_coverage_attrs.py
language: python
files: ^crates/.*\.rs$
- repo: https://github.com/BlankSpruce/gersemi-pre-commit
rev: e98930bdc210d3387007f9252d8c1694ea7e410f # frozen: 0.27.7

View File

@@ -41,6 +41,7 @@ Version 3.4.0 is not yet released. These changes are available in the 3.4.0 beta
- `gateway_balances`: The `account` and `ident` fields now return an `invalidParams` error if the value is not a string, instead of an `internal` error. [#7655](https://github.com/XRPLF/rippled/pull/7655)
- `account_lines`: The `peer` field now returns an error if the value is not a string. [#7728](https://github.com/XRPLF/rippled/pull/7728)
- `ledger`: `delivered_amount` is now included in the metadata of successful `AccountDelete` transactions when transactions are expanded (`expand`, or admin-only `full`). Previously it was only added for `Payment` and `CheckCash`, which made `ledger` inconsistent with `tx` and `account_tx`. [#5706](https://github.com/XRPLF/rippled/pull/5706)
- `submit`: Augmented response fields (`accepted`, `applied`, `broadcast`, `queued`, `kept`, `account_sequence_next`, `account_sequence_available`, `open_ledger_cost`, `validated_ledger_index`) are now included in sign-and-submit mode. Previously, these fields were only returned when submitting a binary transaction blob. ([#6304](https://github.com/XRPLF/rippled/pull/6304))
## XRP Ledger server version 3.3.0

View File

@@ -158,6 +158,7 @@ if [ "${os}" = "linux" ] || [ "${os}" = "macos" ]; then
check cargo-nextest cargo nextest --version
check clippy-driver
check rust-analyzer
check rust-nightly rust-nightly run rustc --version
check rustc
check rustfmt
fi

View File

@@ -0,0 +1,149 @@
#!/usr/bin/env python3
"""
Check that Rust unit tests stay out of the coverage report.
cargo-llvm-cov instruments the test code along with everything else, so a test
module that is not excluded counts its own body as covered and inflates the
reported number. Excluding it takes two attributes:
* every `#[cfg(test)]` module carries
`#[cfg_attr(coverage_nightly, coverage(off))]`;
* every crate root (lib.rs, main.rs) carries
`#![cfg_attr(coverage_nightly, feature(coverage_attribute))]`, which the
attribute above needs in order to compile.
Both are inert outside the coverage job: cargo-llvm-cov defines
`coverage_nightly` only when it runs on a nightly toolchain.
The crate-root gate is checked even in a crate that has no tests yet, because
that is what lets the first test module added later carry the attribute without
a build failure. Missing it is a hard error, so it cannot go unnoticed; a
missing `coverage(off)` fails open, which is why this check exists.
Matching is on exact attribute text, which works because `cargo fmt` runs over
the whole workspace in the hook ahead of this one: rustfmt puts every attribute
on its own line and normalizes what is inside it, turning `#[cfg( test )]`
and `#[cfg(test,)]` alike into `#[cfg(test)]`. So there is nothing here that
parses Rust. The price is that a cfg this file does not spell out literally --
`all(test, ...)`, `any(test, ...)`, `not(test)` -- is reported rather than
classified, on the grounds that guessing at coverage semantics is how a check
like this ends up quietly wrong.
Usage: ./bin/pre-commit/check_rust_coverage_attrs.py <file1> <file2> ...
Exit status is non-zero if any violation is found.
"""
import re
import sys
from dataclasses import dataclass
from pathlib import Path
CRATE_ROOTS = {"lib.rs", "main.rs"}
FEATURE_ATTR = "#![cfg_attr(coverage_nightly, feature(coverage_attribute))]"
COVERAGE_OFF_ATTR = "#[cfg_attr(coverage_nightly, coverage(off))]"
CFG_TEST_ATTR = "#[cfg(test)]"
# Any other cfg that mentions `test`. String literals are blanked before this
# runs, so `feature = "test"` does not read as the `test` cfg.
RE_CFG_MENTIONS_TEST = re.compile(r"^#\[cfg\(.*\btest\b.*\)\]$")
RE_STRING = re.compile(r'"(?:[^"\\]|\\.)*"')
RE_MOD = re.compile(r"^(?:pub(?:\([^)]*\))?\s+)?mod\s+([A-Za-z_]\w*)")
@dataclass(frozen=True)
class Finding:
line: int
label: str
message: str
def _check_module(attrs: list[str], line: int, name: str) -> list[Finding]:
"""Findings for one module, given the attributes attached to it."""
if COVERAGE_OFF_ATTR in attrs:
return [] # excluded from coverage; which cfg gates it does not matter
if CFG_TEST_ATTR in attrs:
return [
Finding(
line,
"missing-coverage-off",
f"`mod {name}` is #[cfg(test)] but not excluded from coverage; "
f"add {COVERAGE_OFF_ATTR}",
)
]
unclassified = [
attr for attr in attrs if RE_CFG_MENTIONS_TEST.match(RE_STRING.sub('""', attr))
]
if unclassified:
return [
Finding(
line,
"unclassified-cfg",
f"`mod {name}` is gated on {unclassified[0]}, which this check "
f"cannot tell apart from a module that ships in the library; "
f"add {COVERAGE_OFF_ATTR} if it is test-only, or teach this "
f"check the cfg if it is not",
)
]
return []
def _check_test_modules(lines: list[str]) -> list[Finding]:
"""Findings for every test module that is not excluded from coverage."""
findings: list[Finding] = []
attrs: list[str] = []
attrs_line = 0
for number, raw in enumerate(lines, start=1):
stripped = raw.strip()
# Blank lines and comments are allowed between an attribute and its item.
if not stripped or stripped.startswith("//"):
continue
if stripped.startswith("#["):
if not attrs:
attrs_line = number
attrs.append(stripped)
continue
module = RE_MOD.match(stripped)
if module is not None and attrs:
findings += _check_module(attrs, attrs_line, module.group(1))
attrs = []
return findings
def _check_crate_root(name: str, lines: list[str]) -> list[Finding]:
"""A finding if a crate root is missing the coverage_attribute feature gate."""
if name not in CRATE_ROOTS:
return []
if any(line.strip() == FEATURE_ATTR for line in lines):
return []
return [
Finding(
1,
"missing-feature-gate",
f"crate root is missing {FEATURE_ATTR}",
)
]
def check_source(name: str, text: str) -> list[Finding]:
"""Findings for one file's contents; `name` is its base name (lib.rs, ...)."""
lines = text.splitlines()
return _check_crate_root(name, lines) + _check_test_modules(lines)
def check_file(path: Path) -> list[Finding]:
return check_source(path.name, path.read_text(encoding="utf-8"))
def main() -> int:
total = 0
for path in (Path(name) for name in sys.argv[1:]):
for finding in check_file(path):
total += 1
print(f"{path}:{finding.line}: {finding.label}: {finding.message}")
return 1 if total else 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -8,6 +8,9 @@ cxx = { version = "1.0.198", features = ["c++20"] }
[workspace.package]
edition = "2024"
[workspace.lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = [ 'cfg(coverage)', 'cfg(coverage_nightly)' ] }
[profile.release]
opt-level = 3
overflow-checks = true

View File

@@ -8,3 +8,6 @@ crate-type = ["staticlib"]
[dependencies]
cxx.workspace = true
[lints]
workspace = true

View File

@@ -1,3 +1,5 @@
#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
#[cxx::bridge(namespace = "rs::hello_world")]
mod ffi {
extern "Rust" {
@@ -8,3 +10,14 @@ mod ffi {
pub fn hello_world() -> String {
"hello_world".to_string()
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use super::*;
#[test]
fn hello_world_returns_hello_world() {
assert_eq!(hello_world(), "hello_world")
}
}

View File

@@ -131,6 +131,9 @@ Rust toolchain:
✅ rust-analyzer
rust-analyzer 1.97.1 (8bab26f4 2026-07-14)
/nix/store/j6apc5pmd0giy15da9p650r8zklslmvi-rust-analyzer-preview-1.97.1-aarch64-apple-darwin/bin/rust-analyzer
✅ rust-nightly
rustc 1.99.0-nightly (87e5904f5 2026-07-20)
/nix/store/fqpjz4l0nsnji8b2pz57mnj0akbp6hcl-rust-nightly/bin/rust-nightly
✅ rustc
rustc 1.97.1 (8bab26f4f 2026-07-14)
/nix/store/bnfk1sl4s9angb0vj1cj9a5y5zvqinwy-rust-minimal-1.97.1/bin/rustc
@@ -140,4 +143,4 @@ Rust toolchain:
Skipping git-over-HTTPS check (CHECK_TOOLS_SKIP_CLONE is set).
✅ All 44 checked tools are present and runnable.
✅ All 45 checked tools are present and runnable.

View File

@@ -131,6 +131,9 @@ Rust toolchain:
✅ rust-analyzer
rust-analyzer 1.97.1 (8bab26f 2026-07-14)
/nix/store/lr3m97p3hx1k22a7c44pb0wa7rbayhfi-rust-analyzer-preview-1.97.1-x86_64-unknown-linux-gnu/bin/rust-analyzer
✅ rust-nightly
rustc 1.99.0-nightly (87e5904f5 2026-07-20)
/nix/store/j7kf7a5h4xypzp6x1skg4dsdx2k4fwb3-rust-nightly/bin/rust-nightly
✅ rustc
rustc 1.97.1 (8bab26f4f 2026-07-14)
/nix/store/40d3mzka7r1ps71l0yv2fs6616nbw85m-rust-minimal-1.97.1/bin/rustc
@@ -168,4 +171,4 @@ Mold:
Skipping git-over-HTTPS check (CHECK_TOOLS_SKIP_CLONE is set).
✅ All 52 checked tools are present and runnable.
✅ All 53 checked tools are present and runnable.

View File

@@ -131,6 +131,9 @@ Rust toolchain:
✅ rust-analyzer
rust-analyzer 1.97.1 (8bab26f 2026-07-14)
/nix/store/262830dlw2517lnagfx7i7agqgl4fmsd-rust-analyzer-preview-1.97.1-aarch64-unknown-linux-gnu/bin/rust-analyzer
✅ rust-nightly
rustc 1.99.0-nightly (87e5904f5 2026-07-20)
/nix/store/c59pxk1yikdlf129qwyg4fplmxcrha0k-rust-nightly/bin/rust-nightly
✅ rustc
rustc 1.97.1 (8bab26f4f 2026-07-14)
/nix/store/a6p27cg6b8szfixfyvkssx6l0c345zw8-rust-minimal-1.97.1/bin/rustc
@@ -168,4 +171,4 @@ Mold:
Skipping git-over-HTTPS check (CHECK_TOOLS_SKIP_CLONE is set).
✅ All 52 checked tools are present and runnable.
✅ All 53 checked tools are present and runnable.

View File

@@ -2,20 +2,104 @@
#include <test/jtx/Env.h>
#include <test/jtx/JTx.h>
#include <test/jtx/amount.h>
#include <test/jtx/envconfig.h>
#include <test/jtx/pay.h>
#include <xrpld/core/Config.h>
#include <xrpl/basics/strHex.h>
#include <xrpl/beast/unit_test/suite.h>
#include <xrpl/config/Constants.h>
#include <xrpl/json/json_value.h>
#include <xrpl/json/to_string.h>
#include <xrpl/protocol/Seed.h>
#include <xrpl/protocol/Serializer.h>
#include <xrpl/protocol/jss.h>
#include <memory>
namespace xrpl::test {
class Submit_test : public beast::unit_test::Suite
{
public:
void
testAugmentedFields()
{
testcase("Augmented fields in sign-and-submit mode");
using namespace jtx;
// Enable signing support in config
Env env{*this, envconfig([](std::unique_ptr<Config> cfg) {
static std::string const kSigningSupportCfg =
std::string("[") + Sections::kSigningSupport + "]\ntrue";
cfg->loadFromString(kSigningSupportCfg);
return cfg;
})};
Account const alice{"alice"};
Account const bob{"bob"};
env.fund(XRP(10000), alice, bob);
env.close();
// Test 1: Sign-and-submit mode should return augmented fields
{
json::Value jv;
jv[jss::tx_json][jss::TransactionType] = jss::Payment;
jv[jss::tx_json][jss::Account] = alice.human();
jv[jss::tx_json][jss::Destination] = bob.human();
jv[jss::tx_json][jss::Amount] = XRP(100).value().getJson();
jv[jss::secret] = alice.name();
auto const result = env.rpc("json", "submit", to_string(jv))[jss::result];
// These are the augmented fields that should be present
BEAST_EXPECT(result.isMember(jss::engine_result));
BEAST_EXPECT(result.isMember(jss::engine_result_code));
BEAST_EXPECT(result.isMember(jss::engine_result_message));
// New augmented fields from issue #3125
BEAST_EXPECT(result.isMember(jss::accepted));
BEAST_EXPECT(result.isMember(jss::applied));
BEAST_EXPECT(result.isMember(jss::broadcast));
BEAST_EXPECT(result.isMember(jss::queued));
BEAST_EXPECT(result.isMember(jss::kept));
// Current ledger state fields
BEAST_EXPECT(result.isMember(jss::account_sequence_next));
BEAST_EXPECT(result.isMember(jss::account_sequence_available));
BEAST_EXPECT(result.isMember(jss::open_ledger_cost));
BEAST_EXPECT(result.isMember(jss::validated_ledger_index));
// Verify basic transaction fields
BEAST_EXPECT(result.isMember(jss::tx_blob));
BEAST_EXPECT(result.isMember(jss::tx_json));
}
// Test 2: Binary blob mode should also return augmented fields (regression test)
{
auto jt = env.jt(pay(alice, bob, XRP(100)));
Serializer s;
jt.stx->add(s);
auto const result = env.rpc("submit", strHex(s.slice()))[jss::result];
// Verify augmented fields are present in binary mode too
BEAST_EXPECT(result.isMember(jss::engine_result));
BEAST_EXPECT(result.isMember(jss::accepted));
BEAST_EXPECT(result.isMember(jss::applied));
BEAST_EXPECT(result.isMember(jss::broadcast));
BEAST_EXPECT(result.isMember(jss::queued));
BEAST_EXPECT(result.isMember(jss::kept));
BEAST_EXPECT(result.isMember(jss::account_sequence_next));
BEAST_EXPECT(result.isMember(jss::account_sequence_available));
BEAST_EXPECT(result.isMember(jss::open_ledger_cost));
BEAST_EXPECT(result.isMember(jss::validated_ledger_index));
}
}
void
testFailHardValidation()
{
@@ -89,6 +173,7 @@ public:
void
run() override
{
testAugmentedFields();
testFailHardValidation();
}
};

View File

@@ -19,6 +19,7 @@
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/contract.h>
#include <xrpl/basics/safe_cast.h>
#include <xrpl/basics/strHex.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/core/NetworkIDService.h>
@@ -809,6 +810,8 @@ transactionFormatResultImpl(Transaction::pointer tpTrans, unsigned apiVersion)
jvResult[jss::engine_result] = sToken;
jvResult[jss::engine_result_code] = tpTrans->getResult();
jvResult[jss::engine_result_message] = sHuman;
rpc::populateAugmentedSubmitFields(jvResult, tpTrans);
}
}
catch (std::exception&)
@@ -822,6 +825,33 @@ transactionFormatResultImpl(Transaction::pointer tpTrans, unsigned apiVersion)
//------------------------------------------------------------------------------
void
populateAugmentedSubmitFields(
json::Value& jvResult,
std::shared_ptr<Transaction> const& transaction)
{
auto const submitResult = transaction->getSubmitResult();
jvResult[jss::accepted] = submitResult.any();
jvResult[jss::applied] = submitResult.applied;
jvResult[jss::broadcast] = submitResult.broadcast;
jvResult[jss::queued] = submitResult.queued;
jvResult[jss::kept] = submitResult.kept;
if (auto currentLedgerState = transaction->getCurrentLedgerState())
{
jvResult[jss::account_sequence_next] =
safeCast<json::Value::UInt>(currentLedgerState->accountSeqNext);
jvResult[jss::account_sequence_available] =
safeCast<json::Value::UInt>(currentLedgerState->accountSeqAvail);
jvResult[jss::open_ledger_cost] = to_string(currentLedgerState->minFeeRequired);
jvResult[jss::validated_ledger_index] =
safeCast<json::Value::UInt>(currentLedgerState->validatedLedger);
}
}
//------------------------------------------------------------------------------
[[nodiscard]] static XRPAmount
getTxFee(Application const& app, Config const& config, json::Value tx)
{

View File

@@ -22,6 +22,21 @@ class TxQ;
namespace rpc {
/**
* Populate augmented submit fields into a JSON result.
* This helper populates the submit result flags (accepted, applied,
* broadcast, queued, kept) and current ledger state fields
* (account_sequence_next, account_sequence_available, open_ledger_cost,
* validated_ledger_index) from a Transaction pointer.
*
* @param jvResult The JSON result to populate
* @param transaction The transaction containing the submit result and state
*/
void
populateAugmentedSubmitFields(
json::Value& jvResult,
std::shared_ptr<Transaction> const& transaction);
json::Value
getCurrentNetworkFee(
Role const role,

View File

@@ -6,7 +6,6 @@
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/StringUtilities.h>
#include <xrpl/basics/safe_cast.h>
#include <xrpl/basics/strHex.h>
#include <xrpl/json/json_value.h>
#include <xrpl/protocol/ErrorCodes.h>
@@ -14,7 +13,6 @@
#include <xrpl/protocol/STTx.h>
#include <xrpl/protocol/Serializer.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/XRPAmount.h>
#include <xrpl/protocol/jss.h>
#include <xrpl/resource/Fees.h>
#include <xrpl/tx/apply.h>
@@ -155,24 +153,7 @@ doSubmit(rpc::JsonContext& context)
jvResult[jss::engine_result_code] = transaction->getResult();
jvResult[jss::engine_result_message] = sHuman;
auto const submitResult = transaction->getSubmitResult();
jvResult[jss::accepted] = submitResult.any();
jvResult[jss::applied] = submitResult.applied;
jvResult[jss::broadcast] = submitResult.broadcast;
jvResult[jss::queued] = submitResult.queued;
jvResult[jss::kept] = submitResult.kept;
if (auto currentLedgerState = transaction->getCurrentLedgerState())
{
jvResult[jss::account_sequence_next] =
safeCast<json::Value::UInt>(currentLedgerState->accountSeqNext);
jvResult[jss::account_sequence_available] =
safeCast<json::Value::UInt>(currentLedgerState->accountSeqAvail);
jvResult[jss::open_ledger_cost] = to_string(currentLedgerState->minFeeRequired);
jvResult[jss::validated_ledger_index] =
safeCast<json::Value::UInt>(currentLedgerState->validatedLedger);
}
rpc::populateAugmentedSubmitFields(jvResult, transaction);
}
return jvResult;