Skip to content

Commit 2cfd4e7

Browse files
committed
paymentsdb: implement RegisterAttempt for sql backend
1 parent 6b8bed6 commit 2cfd4e7

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
)
@@ -730,3 +732,195 @@ func (s *SQLStore) InitPayment(paymentHash lntypes.Hash,
730732

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

0 commit comments

Comments
 (0)