From 2fc0a6e9f757d0f2330c48729ac21f14dc1a5f6f Mon Sep 17 00:00:00 2001 From: Fmar Date: Thu, 28 Dec 2023 00:35:08 +0100 Subject: [PATCH] implement republish invoice --- Dockerfile | 4 +++ README.md | 11 +++++++- .../main.go | 26 +++++++++++++------ config/config.go | 21 ++++++++------- lnd/interface.go | 1 + lnd/lnd.go | 4 +++ service/service.go | 16 ++++++++++++ 7 files changed, 64 insertions(+), 19 deletions(-) rename cmd/{publish-invoices => republish-invoices}/main.go (75%) diff --git a/Dockerfile b/Dockerfile index 42c3993..ef2923b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,10 +14,14 @@ COPY . . # Build the application RUN go build -o main +# Build the utility scripts +RUN go build ./cmd/republish-invoices + # Start a new, final image to reduce size. FROM alpine as final # Copy the binaries and entrypoint from the builder image. COPY --from=builder /build/main /bin/ +COPY --from=builder /build/republish-invoices /bin/ ENTRYPOINT [ "/bin/main" ] diff --git a/README.md b/README.md index 1bb8143..8e22456 100644 --- a/README.md +++ b/README.md @@ -22,4 +22,13 @@ Possible missed-while-offline outgoing payments are handled by looking up the ea - Routing key: `invoice.incoming.settled` # LND outgoing payments - Payload [lnrpc.Payment](https://github.com/lightningnetwork/lnd/blob/master/lnrpc/lightning.pb.go#L12612) -- Routing keys `payment.outgoing.settled`, `payment.outgoing.error` \ No newline at end of file +- Routing keys `payment.outgoing.settled`, `payment.outgoing.error` + +# REPUBLISH INVOICES + +If you need to republish settled invoices to update state in lndhub, you can use the cmd/republish-invoices by providing all payment hashes separated by commas: +- "REPUBLISH_INVOICE_HASHES" : `,....` + +Use this in a job by setting: +```command: +- /bin/republish-invoices``` diff --git a/cmd/publish-invoices/main.go b/cmd/republish-invoices/main.go similarity index 75% rename from cmd/publish-invoices/main.go rename to cmd/republish-invoices/main.go index bb48690..db07810 100644 --- a/cmd/publish-invoices/main.go +++ b/cmd/republish-invoices/main.go @@ -2,8 +2,8 @@ package main import ( "context" + "encoding/hex" "github.com/getAlby/ln-event-publisher/config" - "github.com/getAlby/ln-event-publisher/db" "github.com/getAlby/ln-event-publisher/lnd" "github.com/getAlby/ln-event-publisher/service" "github.com/getsentry/sentry-go" @@ -11,6 +11,8 @@ import ( "github.com/kelseyhightower/envconfig" "github.com/lightningnetwork/lnd/lnrpc" "github.com/sirupsen/logrus" + "os" + "os/signal" ) func main() { @@ -50,21 +52,29 @@ func main() { logrus.Fatal(err) } logrus.Infof("Connected to LND: %s - %s", resp.Alias, resp.IdentityPubkey) - logrus.Info("Opening PG database") - db, err := db.OpenDB(c) - if err != nil { - sentry.CaptureException(err) - logrus.Fatal(err) - } svc := &service.Service{ Cfg: c, Lnd: client, - Db: db, } err = svc.InitRabbitMq() if err != nil { sentry.CaptureException(err) logrus.Fatal(err) } + backgroundCtx := context.Background() + ctx, _ := signal.NotifyContext(backgroundCtx, os.Interrupt) + for i := 0; i < len(c.RepublishInvoiceHashes); i++ { + hashBytes, err := hex.DecodeString(c.RepublishInvoiceHashes[i]) + if err != nil { + logrus.Error("Invalid Hash ", c.RepublishInvoiceHashes[i], " ", err) + continue + } + + // Create a PaymentHash struct + paymentHash := &lnrpc.PaymentHash{ + RHash: hashBytes, + } + svc.RepublishInvoice(ctx, paymentHash) + } } diff --git a/config/config.go b/config/config.go index 0673f79..08f45b9 100644 --- a/config/config.go +++ b/config/config.go @@ -1,14 +1,15 @@ package config type Config struct { - LNDAddress string `envconfig:"LND_ADDRESS" required:"true"` - LNDMacaroonFile string `envconfig:"LND_MACAROON_FILE"` - LNDCertFile string `envconfig:"LND_CERT_FILE"` - DatabaseUri string `envconfig:"DATABASE_URI" required:"true"` - DatabaseMaxConns int `envconfig:"DATABASE_MAX_CONNS" default:"10"` - DatabaseMaxIdleConns int `envconfig:"DATABASE_MAX_IDLE_CONNS" default:"5"` - DatabaseConnMaxLifetime int `envconfig:"DATABASE_CONN_MAX_LIFETIME" default:"1800"` // 30 minutes - RabbitMQUri string `envconfig:"RABBITMQ_URI" required:"true"` - RabbitMQTimeoutSeconds int `envconfig:"RABBITMQ_TIMEOUT_SECONDS" default:"10"` - SentryDSN string `envconfig:"SENTRY_DSN"` + LNDAddress string `envconfig:"LND_ADDRESS" required:"true"` + LNDMacaroonFile string `envconfig:"LND_MACAROON_FILE"` + LNDCertFile string `envconfig:"LND_CERT_FILE"` + DatabaseUri string `envconfig:"DATABASE_URI" required:"true"` + DatabaseMaxConns int `envconfig:"DATABASE_MAX_CONNS" default:"10"` + DatabaseMaxIdleConns int `envconfig:"DATABASE_MAX_IDLE_CONNS" default:"5"` + DatabaseConnMaxLifetime int `envconfig:"DATABASE_CONN_MAX_LIFETIME" default:"1800"` // 30 minutes + RabbitMQUri string `envconfig:"RABBITMQ_URI" required:"true"` + RabbitMQTimeoutSeconds int `envconfig:"RABBITMQ_TIMEOUT_SECONDS" default:"10"` + SentryDSN string `envconfig:"SENTRY_DSN"` + RepublishInvoiceHashes []string `envconfig:"REPUBLISH_INVOICE_HASHES"` } diff --git a/lnd/interface.go b/lnd/interface.go index ad5f591..8521c9b 100644 --- a/lnd/interface.go +++ b/lnd/interface.go @@ -18,6 +18,7 @@ type LightningClientWrapper interface { GetInfo(ctx context.Context, req *lnrpc.GetInfoRequest, options ...grpc.CallOption) (*lnrpc.GetInfoResponse, error) DecodeBolt11(ctx context.Context, bolt11 string, options ...grpc.CallOption) (*lnrpc.PayReq, error) ListPayments(ctx context.Context, req *lnrpc.ListPaymentsRequest, options ...grpc.CallOption) (*lnrpc.ListPaymentsResponse, error) + LookupInvoice(ctx context.Context, req *lnrpc.PaymentHash, options ...grpc.CallOption) (*lnrpc.Invoice, error) } type SubscribeInvoicesWrapper interface { diff --git a/lnd/lnd.go b/lnd/lnd.go index af584db..f8655d5 100644 --- a/lnd/lnd.go +++ b/lnd/lnd.go @@ -139,3 +139,7 @@ func (wrapper *LNDWrapper) SubscribePayments(ctx context.Context, req *routerrpc func (wrapper *LNDWrapper) ListPayments(ctx context.Context, req *lnrpc.ListPaymentsRequest, options ...grpc.CallOption) (*lnrpc.ListPaymentsResponse, error) { return wrapper.client.ListPayments(ctx, req) } + +func (wrapper *LNDWrapper) LookupInvoice(ctx context.Context, req *lnrpc.PaymentHash, options ...grpc.CallOption) (*lnrpc.Invoice, error) { + return wrapper.client.LookupInvoice(ctx, req) +} diff --git a/service/service.go b/service/service.go index ab50958..c94612a 100644 --- a/service/service.go +++ b/service/service.go @@ -388,3 +388,19 @@ func (svc *Service) PublishPayload(ctx context.Context, payload interface{}, exc return err } + +func (svc *Service) RepublishInvoice(ctx context.Context, paymentHash *lnrpc.PaymentHash) { + invoice, err := svc.Lnd.LookupInvoice(ctx, paymentHash) + if err != nil { + sentry.CaptureException(err) + logrus.Error("Invoice NOT FOUND ", paymentHash, err) + return + } + err = svc.ProcessInvoice(ctx, invoice) + if err != nil { + sentry.CaptureException(err) + logrus.Error("ERROR while trying to republish invoice ", paymentHash, err) + } else { + logrus.Info("Invoice Republished ", paymentHash, err) + } +}