mirror of
https://github.com/XRPLF/rippled.git
synced 2026-03-04 03:42:27 +00:00
Compare commits
15 Commits
legleux/tr
...
copilot/ad
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f68f50feb8 | ||
|
|
afc660a1b5 | ||
|
|
05f20ed3d2 | ||
|
|
e1ef9c203a | ||
|
|
8a1c4853f0 | ||
|
|
980b152dca | ||
|
|
e15e332130 | ||
|
|
f66a60c842 | ||
|
|
af5e8ebad1 | ||
|
|
7fac09ccc3 | ||
|
|
d18a9e2e54 | ||
|
|
a7abee3c7b | ||
|
|
0affb48188 | ||
|
|
c0f1a1f094 | ||
|
|
72bf625bfe |
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -176,6 +176,8 @@ words:
|
||||
- nixfmt
|
||||
- nixos
|
||||
- nixpkgs
|
||||
- NOLINT
|
||||
- NOLINTNEXTLINE
|
||||
- nonxrp
|
||||
- noripple
|
||||
- nudb
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1126,8 +1126,8 @@ toClaim(STTx const& tx)
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -339,8 +339,8 @@ validDocumentID(AnyValue const& v)
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace oracle
|
||||
|
||||
@@ -107,6 +107,7 @@ class WSClientImpl : public WSClient
|
||||
{
|
||||
stream_.cancel();
|
||||
}
|
||||
// NOLINTNEXTLINE(bugprone-empty-catch)
|
||||
catch (boost::system::system_error const&)
|
||||
{
|
||||
// ignored
|
||||
|
||||
96
src/test/rpc/Submit_test.cpp
Normal file
96
src/test/rpc/Submit_test.cpp
Normal 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
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ SkipListAcquire::processData(
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
catch (...) // NOLINT(bugprone-empty-catch)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {};
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user