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