From 972841ae29da9bd2838bf2bc3b96c725c68af08b Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Fri, 7 Nov 2025 15:40:50 -0500 Subject: [PATCH] Check for Grace Period overflow in LoanSet --- src/xrpld/app/tx/detail/LoanSet.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/xrpld/app/tx/detail/LoanSet.cpp b/src/xrpld/app/tx/detail/LoanSet.cpp index d8366dc14a..1ef78b11b6 100644 --- a/src/xrpld/app/tx/detail/LoanSet.cpp +++ b/src/xrpld/app/tx/detail/LoanSet.cpp @@ -192,8 +192,8 @@ LoanSet::preclaim(PreclaimContext const& ctx) { // Check for numeric overflow of the schedule before we load any - // objects. NextPaymentDue date for the last payment is: - // startDate + (paymentInterval * paymentTotal). + // objects. The Grace Period for the last payment ends at: + // startDate + (paymentInterval * paymentTotal) + gracePeriod. // If that value is larger than "maxTime", the value // overflows, and we kill the transaction. using timeType = decltype(sfNextPaymentDueDate)::type::value_type; @@ -207,6 +207,13 @@ LoanSet::preclaim(PreclaimContext const& ctx) ctx.tx.at(~sfPaymentInterval).value_or(defaultPaymentInterval); auto const total = ctx.tx.at(~sfPaymentTotal).value_or(defaultPaymentTotal); + auto const grace = + ctx.tx.at(~sfGracePeriod).value_or(defaultGracePeriod); + + // The grace period can't be larger than the interval. Check it first, + // mostly so that unit tests can test that specific case. + if (grace > timeAvailable) + return tecKILLED; if (interval > timeAvailable) return tecKILLED; @@ -214,7 +221,9 @@ LoanSet::preclaim(PreclaimContext const& ctx) if (total > timeAvailable) return tecKILLED; - if (timeAvailable / interval < total) + auto const timeLastPayment = timeAvailable - grace; + + if (timeLastPayment / interval < total) return tecKILLED; }