Skip to content

Commit f6b2ffb

Browse files
committed
paymentsdb: implement RegisterAttempt for sql backend
1 parent 8de92c7 commit f6b2ffb

File tree

1 file changed

+194
-0
lines changed

1 file changed

+194
-0
lines changed

payments/db/sql_store.go

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ import (
66
"errors"
77
"fmt"
88
"math"
9+
"strconv"
910
"time"
1011

1112
"github.com/lightningnetwork/lnd/lntypes"
1213
"github.com/lightningnetwork/lnd/lnwire"
14+
"github.com/lightningnetwork/lnd/routing/route"
1315
"github.com/lightningnetwork/lnd/sqldb"
1416
"github.com/lightningnetwork/lnd/sqldb/sqlc"
1517
)
@@ -732,3 +734,195 @@ func (s *SQLStore) InitPayment(paymentHash lntypes.Hash,
732734

733735
return nil
734736
}
737+
738+
// insertRouteHops inserts all route hop data for a given set of hops.
739+
func (s *SQLStore) insertRouteHops(ctx context.Context, db SQLQueries,
740+
hops []*route.Hop, attemptID uint64) error {
741+
742+
for i, hop := range hops {
743+
// Insert the basic route hop data and get the generated ID
744+
hopID, err := db.InsertRouteHop(ctx, sqlc.InsertRouteHopParams{
745+
HtlcAttemptIndex: int64(attemptID),
746+
HopIndex: int32(i),
747+
PubKey: hop.PubKeyBytes[:],
748+
Scid: strconv.FormatUint(
749+
hop.ChannelID, 10,
750+
),
751+
OutgoingTimeLock: int32(hop.OutgoingTimeLock),
752+
AmtToForward: int64(hop.AmtToForward),
753+
MetaData: hop.Metadata,
754+
})
755+
if err != nil {
756+
return fmt.Errorf("failed to insert route hop: %w", err)
757+
}
758+
759+
// Insert the per-hop custom records
760+
if len(hop.CustomRecords) > 0 {
761+
for key, value := range hop.CustomRecords {
762+
err = db.InsertPaymentHopCustomRecord(ctx, sqlc.InsertPaymentHopCustomRecordParams{
763+
HopID: hopID,
764+
Key: int64(key),
765+
Value: value,
766+
})
767+
if err != nil {
768+
return fmt.Errorf("failed to insert "+
769+
"payment hop custom record: %w", err)
770+
}
771+
}
772+
}
773+
774+
// Insert MPP data if present
775+
if hop.MPP != nil {
776+
paymentAddr := hop.MPP.PaymentAddr()
777+
err = db.InsertRouteHopMpp(ctx, sqlc.InsertRouteHopMppParams{
778+
HopID: hopID,
779+
PaymentAddr: paymentAddr[:],
780+
TotalMsat: int64(hop.MPP.TotalMsat()),
781+
})
782+
if err != nil {
783+
return fmt.Errorf("failed to insert "+
784+
"route hop MPP: %w", err)
785+
}
786+
}
787+
788+
// Insert AMP data if present
789+
if hop.AMP != nil {
790+
rootShare := hop.AMP.RootShare()
791+
setID := hop.AMP.SetID()
792+
err = db.InsertRouteHopAmp(ctx, sqlc.InsertRouteHopAmpParams{
793+
HopID: hopID,
794+
RootShare: rootShare[:],
795+
SetID: setID[:],
796+
})
797+
if err != nil {
798+
return fmt.Errorf("failed to insert "+
799+
"route hop AMP: %w", err)
800+
}
801+
}
802+
803+
// Insert blinded route data if present
804+
if hop.EncryptedData != nil || hop.BlindingPoint != nil {
805+
var blindingPointBytes []byte
806+
if hop.BlindingPoint != nil {
807+
blindingPointBytes = hop.BlindingPoint.SerializeCompressed()
808+
}
809+
810+
err = db.InsertRouteHopBlinded(ctx, sqlc.InsertRouteHopBlindedParams{
811+
HopID: hopID,
812+
EncryptedData: hop.EncryptedData,
813+
BlindingPoint: blindingPointBytes,
814+
})
815+
if err != nil {
816+
return fmt.Errorf("failed to insert "+
817+
"route hop blinded: %w", err)
818+
}
819+
}
820+
}
821+
822+
return nil
823+
}
824+
825+
// RegisterAttempt registers an attempt for a payment.
826+
//
827+
// This is part of the DB interface.
828+
func (s *SQLStore) RegisterAttempt(paymentHash lntypes.Hash,
829+
attempt *HTLCAttemptInfo) (*MPPayment, error) {
830+
831+
ctx := context.TODO()
832+
833+
var mpPayment *MPPayment
834+
835+
err := s.db.ExecTx(ctx, sqldb.WriteTxOpt(), func(db SQLQueries) error {
836+
// 1. First Fetch the payment and check if it is registrable.
837+
existingPayment, err := s.db.FetchPayment(ctx, paymentHash[:])
838+
if err != nil {
839+
return fmt.Errorf("failed to fetch payment: %w", err)
840+
}
841+
842+
mpPayment, err = s.fetchPaymentWithCompleteData(
843+
ctx, s.db, existingPayment,
844+
)
845+
if err != nil {
846+
return fmt.Errorf("failed to fetch payment with "+
847+
"complete data: %w", err)
848+
}
849+
850+
if err := mpPayment.Registrable(); err != nil {
851+
return fmt.Errorf("htlc attempt not registrable: %w",
852+
err)
853+
}
854+
855+
// Verify the attempt is compatible with the existing payment.
856+
if err := verifyAttempt(mpPayment, attempt); err != nil {
857+
return fmt.Errorf("failed to verify attempt: %w", err)
858+
}
859+
860+
// Fist register the plain HTLC attempt.
861+
// Prepare the session key.
862+
sessionKey := attempt.SessionKey()
863+
sessionKeyBytes := sessionKey.Serialize()
864+
865+
_, err = db.InsertHtlcAttempt(ctx, sqlc.InsertHtlcAttemptParams{
866+
PaymentID: existingPayment.Payment.ID,
867+
AttemptIndex: int64(attempt.AttemptID),
868+
SessionKey: sessionKeyBytes,
869+
AttemptTime: attempt.AttemptTime,
870+
PaymentHash: paymentHash[:],
871+
FirstHopAmountMsat: int64(
872+
attempt.Route.FirstHopAmount.Val.Int(),
873+
),
874+
RouteTotalTimeLock: int32(attempt.Route.TotalTimeLock),
875+
RouteTotalAmount: int64(attempt.Route.TotalAmount),
876+
RouteSourceKey: attempt.Route.SourcePubKey[:],
877+
})
878+
if err != nil {
879+
return fmt.Errorf("failed to insert HTLC "+
880+
"attempt: %w", err)
881+
}
882+
883+
// Insert the route level first hop custom records.
884+
for key, value := range attempt.Route.FirstHopWireCustomRecords {
885+
err = db.InsertPaymentAttemptFirstHopCustomRecord(ctx,
886+
sqlc.InsertPaymentAttemptFirstHopCustomRecordParams{
887+
HtlcAttemptIndex: int64(attempt.AttemptID),
888+
Key: int64(key),
889+
Value: value,
890+
})
891+
if err != nil {
892+
return fmt.Errorf("failed to insert "+
893+
"payment attempt first hop custom "+
894+
"record: %w", err)
895+
}
896+
}
897+
898+
// Insert the route hops.
899+
err = s.insertRouteHops(
900+
ctx, db, attempt.Route.Hops, attempt.AttemptID,
901+
)
902+
if err != nil {
903+
return fmt.Errorf("failed to insert route hops: %w",
904+
err)
905+
}
906+
907+
// Add the attempt to the payment without fetching it from the
908+
// DB again.
909+
mpPayment.HTLCs = append(mpPayment.HTLCs, HTLCAttempt{
910+
HTLCAttemptInfo: *attempt,
911+
})
912+
913+
mpPayment.SetState()
914+
if err := mpPayment.SetState(); err != nil {
915+
return fmt.Errorf("failed to set payment state: %w",
916+
err)
917+
}
918+
919+
return nil
920+
}, func() {
921+
mpPayment = nil
922+
})
923+
if err != nil {
924+
return nil, fmt.Errorf("failed to register attempt: %w", err)
925+
}
926+
927+
return mpPayment, nil
928+
}

0 commit comments

Comments
 (0)