Compare commits

...

5 Commits

Author SHA1 Message Date
Mayukha Vadari
64b53d6890 add unreachable 2026-03-19 13:50:05 -04:00
Mayukha Vadari
d8f11a9c17 Merge branch 'develop' into mvadari/refactor-tec-deletions 2026-03-19 13:48:33 -04:00
Mayukha Vadari
ceeff478f4 clean up code 2026-03-19 13:38:39 -04:00
Mayukha Vadari
a149cc944a Merge branch 'develop' into mvadari/refactor-tec-deletions 2026-03-19 09:47:28 -04:00
Mayukha Vadari
c4c76e2aaf refactor: Clean up tec object deletion logic 2026-03-19 00:45:45 -04:00

View File

@@ -17,6 +17,9 @@
#include <xrpl/tx/transactors/delegate/DelegateUtils.h>
#include <xrpl/tx/transactors/nft/NFTokenUtils.h>
#include <algorithm>
#include <map>
namespace xrpl {
/** Performs early sanity checks on the txid */
@@ -1133,25 +1136,25 @@ Transactor::operator()()
// awkward and very limiting. A more general purpose approach
// should be used, making it possible to do more useful work
// when transactions fail with a `tec` code.
std::vector<uint256> removedOffers;
std::vector<uint256> removedTrustLines;
std::vector<uint256> expiredNFTokenOffers;
std::vector<uint256> expiredCredentials;
bool const doOffers = ((result == tecOVERSIZE) || (result == tecKILLED));
bool const doLines = (result == tecINCOMPLETE);
bool const doNFTokenOffers = (result == tecEXPIRED);
bool const doCredentials = (result == tecEXPIRED);
if (doOffers || doLines || doNFTokenOffers || doCredentials)
// Build a list of ledger entry types to collect, based on the
// result code. Only deleted objects of these types will be
// re-applied after the context is reset.
std::vector<LedgerEntryType> typesToCollect;
if ((result == tecOVERSIZE) || (result == tecKILLED))
typesToCollect.push_back(ltOFFER);
if (result == tecINCOMPLETE)
typesToCollect.push_back(ltRIPPLE_STATE);
if (result == tecEXPIRED)
{
ctx_.visit([doOffers,
&removedOffers,
doLines,
&removedTrustLines,
doNFTokenOffers,
&expiredNFTokenOffers,
doCredentials,
&expiredCredentials](
typesToCollect.push_back(ltNFTOKEN_OFFER);
typesToCollect.push_back(ltCREDENTIAL);
}
std::map<LedgerEntryType, std::vector<uint256>> deletedObjects;
if (!typesToCollect.empty())
{
ctx_.visit([&typesToCollect, &deletedObjects](
uint256 const& index,
bool isDelete,
std::shared_ptr<SLE const> const& before,
@@ -1162,25 +1165,21 @@ Transactor::operator()()
before && after,
"xrpl::Transactor::operator()::visit : non-null SLE "
"inputs");
if (doOffers && before && after && (before->getType() == ltOFFER) &&
(before->getFieldAmount(sfTakerPays) == after->getFieldAmount(sfTakerPays)))
if (before && after)
{
// Removal of offer found or made unfunded
removedOffers.push_back(index);
auto const type = before->getType();
if (std::ranges::find(typesToCollect, type) != typesToCollect.end())
{
// For offers, only collect unfunded removals
// (where TakerPays is unchanged)
if (type == ltOFFER &&
before->getFieldAmount(sfTakerPays) !=
after->getFieldAmount(sfTakerPays))
return;
deletedObjects[type].push_back(index);
}
}
if (doLines && before && after && (before->getType() == ltRIPPLE_STATE))
{
// Removal of obsolete AMM trust line
removedTrustLines.push_back(index);
}
if (doNFTokenOffers && before && after &&
(before->getType() == ltNFTOKEN_OFFER))
expiredNFTokenOffers.push_back(index);
if (doCredentials && before && after && (before->getType() == ltCREDENTIAL))
expiredCredentials.push_back(index);
}
});
}
@@ -1194,18 +1193,34 @@ Transactor::operator()()
fee = resetResult.second;
}
// If necessary, remove any offers found unfunded during processing
if ((result == tecOVERSIZE) || (result == tecKILLED))
removeUnfundedOffers(view(), removedOffers, ctx_.registry.journal("View"));
// Re-apply the collected deletions
auto const viewJ = ctx_.registry.journal("View");
for (auto const& [type, ids] : deletedObjects)
{
if (ids.empty())
continue;
if (result == tecEXPIRED)
removeExpiredNFTokenOffers(view(), expiredNFTokenOffers, ctx_.registry.journal("View"));
if (result == tecINCOMPLETE)
removeDeletedTrustLines(view(), removedTrustLines, ctx_.registry.journal("View"));
if (result == tecEXPIRED)
removeExpiredCredentials(view(), expiredCredentials, ctx_.registry.journal("View"));
switch (type)
{
case ltOFFER:
removeUnfundedOffers(view(), ids, viewJ);
break;
case ltNFTOKEN_OFFER:
removeExpiredNFTokenOffers(view(), ids, viewJ);
break;
case ltRIPPLE_STATE:
removeDeletedTrustLines(view(), ids, viewJ);
break;
case ltCREDENTIAL:
removeExpiredCredentials(view(), ids, viewJ);
break;
// LCOV_EXCL_START
default:
UNREACHABLE("xrpl::Transactor::operator() : unexpected type");
break;
// LCOV_EXCL_STOP
}
}
applied = isTecClaim(result);
}