@@ -1030,7 +1030,8 @@ func (s *SQLStore) insertRouteHops(ctx context.Context, db SQLQueries,
10301030 })
10311031 if err != nil {
10321032 return fmt .Errorf ("failed to insert " +
1033- "payment hop custom record: %w" , err )
1033+ "payment hop custom " +
1034+ "record: %w" , err )
10341035 }
10351036 }
10361037 }
@@ -1222,3 +1223,70 @@ func (s *SQLStore) RegisterAttempt(paymentHash lntypes.Hash,
12221223
12231224 return mpPayment , nil
12241225}
1226+
1227+ // SettleAttempt marks the specified HTLC attempt as successfully settled,
1228+ // recording the payment preimage and settlement time. The preimage serves as
1229+ // cryptographic proof of payment and is atomically saved to the database.
1230+ //
1231+ // This method is part of the PaymentControl interface, which is embedded in
1232+ // the PaymentWriter interface and ultimately the DB interface. It represents
1233+ // step 3a in the payment lifecycle control flow (step 3b is FailAttempt),
1234+ // called after RegisterAttempt when an HTLC successfully completes.
1235+ func (s * SQLStore ) SettleAttempt (paymentHash lntypes.Hash ,
1236+ attemptID uint64 , settleInfo * HTLCSettleInfo ) (* MPPayment , error ) {
1237+
1238+ ctx := context .TODO ()
1239+
1240+ var mpPayment * MPPayment
1241+
1242+ err := s .db .ExecTx (ctx , sqldb .WriteTxOpt (), func (db SQLQueries ) error {
1243+ // Before updating the attempt, we fetch the payment to get the
1244+ // payment ID.
1245+ payment , err := db .FetchPayment (ctx , paymentHash [:])
1246+ if err != nil && ! errors .Is (err , sql .ErrNoRows ) {
1247+ return fmt .Errorf ("failed to fetch payment: %w" , err )
1248+ }
1249+ if errors .Is (err , sql .ErrNoRows ) {
1250+ return ErrPaymentNotInitiated
1251+ }
1252+ completePayment , err := s .fetchPaymentWithCompleteData (
1253+ ctx , db , payment ,
1254+ )
1255+ if err != nil {
1256+ return fmt .Errorf ("failed to fetch payment with " +
1257+ "complete data: %w" , err )
1258+ }
1259+
1260+ if completePayment .Status .updatable () != nil {
1261+ return fmt .Errorf ("payment is not updatable: %w" ,
1262+ completePayment .Status .updatable ())
1263+ }
1264+
1265+ err = db .SettleAttempt (ctx , sqlc.SettleAttemptParams {
1266+ AttemptIndex : int64 (attemptID ),
1267+ ResolutionTime : time .Now (),
1268+ ResolutionType : int32 (HTLCAttemptResolutionSettled ),
1269+ SettlePreimage : settleInfo .Preimage [:],
1270+ })
1271+ if err != nil {
1272+ return fmt .Errorf ("failed to settle attempt: %w" , err )
1273+ }
1274+
1275+ mpPayment , err = s .fetchPaymentWithCompleteData (
1276+ ctx , db , payment ,
1277+ )
1278+ if err != nil {
1279+ return fmt .Errorf ("failed to fetch payment with " +
1280+ "complete data: %w" , err )
1281+ }
1282+
1283+ return nil
1284+ }, func () {
1285+ mpPayment = nil
1286+ })
1287+ if err != nil {
1288+ return nil , fmt .Errorf ("failed to settle attempt: %w" , err )
1289+ }
1290+
1291+ return mpPayment , nil
1292+ }
0 commit comments