@@ -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