Compare commits

...

15 Commits

Author SHA1 Message Date
Mayukha Vadari
f68f50feb8 Merge branch 'develop' into copilot/add-augmented-submit-fields 2026-03-02 17:06:37 -05:00
Alex Kremer
afc660a1b5 refactor: Fix clang-tidy bugprone-empty-catch check (#6419)
This change fixes or suppresses instances detected by the `bugprone-empty-catch` clang-tidy check.
2026-03-02 17:08:56 +00:00
Mayukha Vadari
05f20ed3d2 Merge branch 'develop' into copilot/add-augmented-submit-fields 2026-02-27 16:41:55 -05:00
Mayukha Vadari
e1ef9c203a Merge branch 'develop' into copilot/add-augmented-submit-fields 2026-02-27 13:49:32 -05:00
Mayukha Vadari
8a1c4853f0 Merge upstream/develop into copilot/add-augmented-submit-fields 2026-02-26 14:33:50 -05:00
Mayukha Vadari
980b152dca Merge branch 'develop' into copilot/add-augmented-submit-fields 2026-02-06 11:43:47 -05:00
Mayukha Vadari
e15e332130 Merge remote-tracking branch 'upstream/develop' into copilot/add-augmented-submit-fields 2026-02-05 13:33:36 -05:00
Mayukha Vadari
f66a60c842 Merge branch 'develop' into copilot/add-augmented-submit-fields 2026-02-04 16:24:53 -05:00
Mayukha Vadari
af5e8ebad1 Merge remote-tracking branch 'origin/develop' into copilot/add-augmented-submit-fields 2026-02-04 16:22:19 -05:00
Mayukha Vadari
7fac09ccc3 fix issues 2026-01-30 12:14:24 -05:00
copilot-swe-agent[bot]
d18a9e2e54 Extract helper function to avoid code duplication and update API-CHANGELOG
Co-authored-by: mvadari <8029314+mvadari@users.noreply.github.com>
2026-01-30 15:55:51 +00:00
copilot-swe-agent[bot]
a7abee3c7b Fix includes in Submit_test.cpp
Co-authored-by: mvadari <8029314+mvadari@users.noreply.github.com>
2026-01-30 15:29:38 +00:00
copilot-swe-agent[bot]
0affb48188 Fix test to properly construct transaction JSON for sign-and-submit
Co-authored-by: mvadari <8029314+mvadari@users.noreply.github.com>
2026-01-30 15:26:10 +00:00
copilot-swe-agent[bot]
c0f1a1f094 Add augmented fields to sign-and-submit mode and create test
Co-authored-by: mvadari <8029314+mvadari@users.noreply.github.com>
2026-01-30 15:24:51 +00:00
copilot-swe-agent[bot]
72bf625bfe Initial plan 2026-01-30 15:20:54 +00:00
25 changed files with 182 additions and 51 deletions

View File

@@ -10,6 +10,7 @@ Checks: "-*,
bugprone-copy-constructor-init,
bugprone-dangling-handle,
bugprone-dynamic-static-initializers,
bugprone-empty-catch,
bugprone-fold-init-type,
bugprone-forward-declaration-namespace,
bugprone-inaccurate-erase,
@@ -83,7 +84,6 @@ Checks: "-*,
# ---
# checks that have some issues that need to be resolved:
#
# bugprone-empty-catch,
# bugprone-crtp-constructor-accessibility,
# bugprone-inc-dec-in-conditions,
# bugprone-reserved-identifier,

View File

@@ -71,6 +71,12 @@ This release contains bug fixes only and no API changes.
This release contains bug fixes only and no API changes.
## Unreleased Changes
### Additions and bugfixes
- `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 2.5.0
[Version 2.5.0](https://github.com/XRPLF/rippled/releases/tag/2.5.0) was released on Jun 24, 2025.

View File

@@ -176,6 +176,8 @@ words:
- nixfmt
- nixos
- nixpkgs
- NOLINT
- NOLINTNEXTLINE
- nonxrp
- noripple
- nudb

View File

@@ -249,7 +249,7 @@ public:
{
m_timer.cancel();
}
catch (boost::system::system_error const&)
catch (boost::system::system_error const&) // NOLINT(bugprone-empty-catch)
{
// ignored
}

View File

@@ -83,7 +83,7 @@ public:
// close can throw and we don't want the destructor to throw.
close();
}
catch (nudb::system_error const&)
catch (nudb::system_error const&) // NOLINT(bugprone-empty-catch)
{
// Don't allow exceptions to propagate out of destructors.
// close() has already logged the error.

View File

@@ -443,6 +443,7 @@ getRate(STAmount const& offerOut, STAmount const& offerIn)
{
if (offerOut == beast::zero)
return 0;
try
{
STAmount r = divide(offerIn, offerOut, noIssue());
@@ -454,12 +455,11 @@ getRate(STAmount const& offerOut, STAmount const& offerIn)
std::uint64_t ret = r.exponent() + 100;
return (ret << (64 - 8)) | r.mantissa();
}
catch (std::exception const&)
catch (...)
{
// overflow -- very bad offer
return 0;
}
// overflow -- very bad offer
return 0;
}
/**

View File

@@ -246,10 +246,10 @@ STTx::checkSign(Rules const& rules, STObject const& sigObject) const
return signingPubKey.empty() ? checkMultiSign(rules, sigObject)
: checkSingleSign(sigObject);
}
catch (std::exception const&)
catch (...)
{
return Unexpected("Internal signature check failure.");
}
return Unexpected("Internal signature check failure.");
}
Expected<void, std::string>

View File

@@ -1126,8 +1126,8 @@ toClaim(STTx const& tx)
}
catch (...)
{
return std::nullopt;
}
return std::nullopt;
}
template <class TAttestation>

View File

@@ -71,7 +71,7 @@ public:
{
setupDatabaseDir(getDatabasePath());
}
catch (std::exception const&)
catch (std::exception const&) // NOLINT(bugprone-empty-catch)
{
}
}
@@ -81,7 +81,7 @@ public:
{
cleanupDatabaseDir(getDatabasePath());
}
catch (std::exception const&)
catch (std::exception const&) // NOLINT(bugprone-empty-catch)
{
}
}

View File

@@ -58,7 +58,7 @@ public:
{
setupDatabaseDir(getDatabasePath());
}
catch (std::exception const&)
catch (std::exception const&) // NOLINT(bugprone-empty-catch)
{
}
}
@@ -68,7 +68,7 @@ public:
{
cleanupDatabaseDir(getDatabasePath());
}
catch (std::exception const&)
catch (std::exception const&) // NOLINT(bugprone-empty-catch)
{
}
}

View File

@@ -587,10 +587,10 @@ Env::st(JTx const& jt)
{
return sterilize(STTx{std::move(*obj)});
}
catch (std::exception const&)
catch (...)
{
return nullptr;
}
return nullptr;
}
std::shared_ptr<STTx const>
@@ -613,10 +613,10 @@ Env::ust(JTx const& jt)
{
return std::make_shared<STTx const>(std::move(*obj));
}
catch (std::exception const&)
catch (...)
{
return nullptr;
}
return nullptr;
}
Json::Value

View File

@@ -339,8 +339,8 @@ validDocumentID(AnyValue const& v)
}
catch (...)
{
return false;
}
return false;
}
} // namespace oracle

View File

@@ -107,6 +107,7 @@ class WSClientImpl : public WSClient
{
stream_.cancel();
}
// NOLINTNEXTLINE(bugprone-empty-catch)
catch (boost::system::system_error const&)
{
// ignored

View File

@@ -0,0 +1,96 @@
#include <test/jtx.h>
#include <xrpld/core/ConfigSections.h>
#include <xrpl/protocol/jss.h>
namespace xrpl {
class Submit_test : public beast::unit_test::suite
{
public:
void
testAugmentedFields()
{
testcase("Augmented fields in sign-and-submit mode");
using namespace test::jtx;
// Enable signing support in config
Env env{*this, envconfig([](std::unique_ptr<Config> cfg) {
cfg->loadFromString("[" SECTION_SIGNING_SUPPORT "]\ntrue");
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(JsonOptions::none);
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
run() override
{
testAugmentedFields();
}
};
BEAST_DEFINE_TESTSUITE(Submit, rpc, xrpl);
} // namespace xrpl

View File

@@ -35,7 +35,7 @@ TEST(scope, scope_exit)
scope_exit x{[&i]() { i = 5; }};
throw 1;
}
catch (...)
catch (...) // NOLINT(bugprone-empty-catch)
{
}
}
@@ -47,7 +47,7 @@ TEST(scope, scope_exit)
x.release();
throw 1;
}
catch (...)
catch (...) // NOLINT(bugprone-empty-catch)
{
}
}
@@ -85,7 +85,7 @@ TEST(scope, scope_fail)
scope_fail x{[&i]() { i = 5; }};
throw 1;
}
catch (...)
catch (...) // NOLINT(bugprone-empty-catch)
{
}
}
@@ -97,7 +97,7 @@ TEST(scope, scope_fail)
x.release();
throw 1;
}
catch (...)
catch (...) // NOLINT(bugprone-empty-catch)
{
}
}
@@ -135,7 +135,7 @@ TEST(scope, scope_success)
scope_success x{[&i]() { i = 5; }};
throw 1;
}
catch (...)
catch (...) // NOLINT(bugprone-empty-catch)
{
}
}
@@ -147,7 +147,7 @@ TEST(scope, scope_success)
x.release();
throw 1;
}
catch (...)
catch (...) // NOLINT(bugprone-empty-catch)
{
}
}

View File

@@ -241,7 +241,7 @@ public:
newNode->getHash().as_uint256(), std::make_shared<Blob>(s.begin(), s.end()));
}
}
catch (std::exception const&)
catch (std::exception const&) // NOLINT(bugprone-empty-catch)
{
}
}

View File

@@ -1637,7 +1637,7 @@ LedgerMaster::getLedgerBySeq(std::uint32_t index)
if (hash)
return mLedgerHistory.getLedgerByHash(*hash);
}
catch (std::exception const&)
catch (std::exception const&) // NOLINT(bugprone-empty-catch)
{
// Missing nodes are already handled
}

View File

@@ -127,7 +127,7 @@ SkipListAcquire::processData(
return;
}
}
catch (...)
catch (...) // NOLINT(bugprone-empty-catch)
{
}

View File

@@ -29,7 +29,7 @@ getEndpoint(std::string const& peer)
if (endpoint)
return beast::IP::to_asio_endpoint(endpoint.value());
}
catch (std::exception const&)
catch (std::exception const&) // NOLINT(bugprone-empty-catch)
{
}
return {};

View File

@@ -177,7 +177,7 @@ ValidatorSite::stop()
{
timer_.cancel();
}
catch (boost::system::system_error const&)
catch (boost::system::system_error const&) // NOLINT(bugprone-empty-catch)
{
}
stopping_ = false;
@@ -222,7 +222,7 @@ ValidatorSite::makeRequest(
{
timer_.cancel_one();
}
catch (boost::system::system_error const&)
catch (boost::system::system_error const&) // NOLINT(bugprone-empty-catch)
{
}
};

View File

@@ -252,7 +252,7 @@ ConnectAttempt::cancelTimer()
timer_.cancel();
stepTimer_.cancel();
}
catch (boost::system::system_error const&)
catch (boost::system::system_error const&) // NOLINT(bugprone-empty-catch)
{
// ignored
}

View File

@@ -1479,7 +1479,7 @@ rpcClient(
setup = setup_ServerHandler(
config, beast::logstream{logs.journal("HTTPClient").warn()});
}
catch (std::exception const&)
catch (std::exception const&) // NOLINT(bugprone-empty-catch)
{
// ignore any exceptions, so the command
// line client works without a config file

View File

@@ -731,6 +731,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&)
@@ -744,6 +746,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] =
safe_cast<Json::Value::UInt>(currentLedgerState->accountSeqNext);
jvResult[jss::account_sequence_available] =
safe_cast<Json::Value::UInt>(currentLedgerState->accountSeqAvail);
jvResult[jss::open_ledger_cost] = to_string(currentLedgerState->minFeeRequired);
jvResult[jss::validated_ledger_index] =
safe_cast<Json::Value::UInt>(currentLedgerState->validatedLedger);
}
}
//------------------------------------------------------------------------------
[[nodiscard]] static XRPAmount
getTxFee(Application const& app, Config const& config, Json::Value tx)
{

View File

@@ -16,6 +16,20 @@ 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

@@ -129,24 +129,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] =
safe_cast<Json::Value::UInt>(currentLedgerState->accountSeqNext);
jvResult[jss::account_sequence_available] =
safe_cast<Json::Value::UInt>(currentLedgerState->accountSeqAvail);
jvResult[jss::open_ledger_cost] = to_string(currentLedgerState->minFeeRequired);
jvResult[jss::validated_ledger_index] =
safe_cast<Json::Value::UInt>(currentLedgerState->validatedLedger);
}
RPC::populateAugmentedSubmitFields(jvResult, transaction);
}
return jvResult;