-
-
Notifications
You must be signed in to change notification settings - Fork 114
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Use parallel invoice subscriptions * Fix missing idempotency * Log error * Use cursor for invoice subscription * Subscribe to outgoing payments for withdrawals * Add TODO comments regarding migration to LND subscriptions * Also use isPoll variable in checkInvoice * Queue status check of pending withdrawals * Use for loop to check pending withdrawals * Reconnect to LND gRPC API on error * Fix hash modified of applied migrations * Separate wallet code from worker index * refactor subscription code some more * remove unnecessary subWrapper abstraction * move all wallet related code into worker/wallet.js such that only a single import is needed in worker/index.js * Migrate from polling to LND subscriptions * Remove unnecessary reconnect code * Add FIXME * Add listener for HODL invoice updates * Remove obsolete comment * Update README * Add job to cancel hodl invoice if expired * Fix missing else * small bug fixes and readability enhancements * refine and add periodic redundant deposit/withdrawal checks --------- Co-authored-by: ekzyis <[email protected]> Co-authored-by: Keyan <[email protected]> Co-authored-by: keyan <[email protected]>
- Loading branch information
1 parent
cb076ec
commit 2151323
Showing
10 changed files
with
310 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
prisma/migrations/20240104004135_invoice_confirmed_index/migration.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
-- AlterTable | ||
ALTER TABLE "Invoice" ADD COLUMN "confirmedIndex" BIGINT; | ||
|
||
-- CreateIndex | ||
CREATE INDEX "Invoice.confirmedIndex_index" ON "Invoice"("confirmedIndex"); |
98 changes: 98 additions & 0 deletions
98
prisma/migrations/20240105190205_replace_polling_with_lnd_subscriptions/migration.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
-- remove 'checkInvoice' job insertion since we're using LND subscriptions now | ||
-- also allow function to take preimage as an argument | ||
DROP FUNCTION IF EXISTS create_invoice(hash TEXT, bolt11 TEXT, expires_at timestamp(3) without time zone, | ||
msats_req BIGINT, user_id INTEGER, idesc TEXT, comment TEXT, lud18_data JSONB, inv_limit INTEGER, balance_limit_msats BIGINT); | ||
CREATE OR REPLACE FUNCTION create_invoice(hash TEXT, preimage TEXT, bolt11 TEXT, expires_at timestamp(3) without time zone, | ||
msats_req BIGINT, user_id INTEGER, idesc TEXT, comment TEXT, lud18_data JSONB, inv_limit INTEGER, balance_limit_msats BIGINT) | ||
RETURNS "Invoice" | ||
LANGUAGE plpgsql | ||
AS $$ | ||
DECLARE | ||
invoice "Invoice"; | ||
inv_limit_reached BOOLEAN; | ||
balance_limit_reached BOOLEAN; | ||
inv_pending_msats BIGINT; | ||
BEGIN | ||
PERFORM ASSERT_SERIALIZED(); | ||
|
||
-- prevent too many pending invoices | ||
SELECT inv_limit > 0 AND count(*) >= inv_limit, COALESCE(sum("msatsRequested"), 0) INTO inv_limit_reached, inv_pending_msats | ||
FROM "Invoice" | ||
WHERE "userId" = user_id AND "expiresAt" > now_utc() AND "confirmedAt" IS NULL AND cancelled = false; | ||
|
||
IF inv_limit_reached THEN | ||
RAISE EXCEPTION 'SN_INV_PENDING_LIMIT'; | ||
END IF; | ||
|
||
-- prevent pending invoices + msats from exceeding the limit | ||
SELECT balance_limit_msats > 0 AND inv_pending_msats+msats_req+msats > balance_limit_msats INTO balance_limit_reached | ||
FROM users | ||
WHERE id = user_id; | ||
|
||
IF balance_limit_reached THEN | ||
RAISE EXCEPTION 'SN_INV_EXCEED_BALANCE'; | ||
END IF; | ||
|
||
-- we good, proceed frens | ||
INSERT INTO "Invoice" (hash, preimage, bolt11, "expiresAt", "msatsRequested", "userId", created_at, updated_at, "desc", comment, "lud18Data") | ||
VALUES (hash, preimage, bolt11, expires_at, msats_req, user_id, now_utc(), now_utc(), idesc, comment, lud18_data) RETURNING * INTO invoice; | ||
|
||
IF preimage IS NOT NULL THEN | ||
INSERT INTO pgboss.job (name, data, retrylimit, retrybackoff, startafter) | ||
VALUES ('finalizeHodlInvoice', jsonb_build_object('hash', hash), 21, true, expires_at); | ||
END IF; | ||
|
||
RETURN invoice; | ||
END; | ||
$$; | ||
|
||
-- remove 'checkWithdrawal' job insertion since we're using LND subscriptions now | ||
CREATE OR REPLACE FUNCTION create_withdrawl(lnd_id TEXT, invoice TEXT, msats_amount BIGINT, msats_max_fee BIGINT, username TEXT) | ||
RETURNS "Withdrawl" | ||
LANGUAGE plpgsql | ||
AS $$ | ||
DECLARE | ||
user_id INTEGER; | ||
user_msats BIGINT; | ||
withdrawl "Withdrawl"; | ||
BEGIN | ||
PERFORM ASSERT_SERIALIZED(); | ||
|
||
SELECT msats, id INTO user_msats, user_id FROM users WHERE name = username; | ||
IF (msats_amount + msats_max_fee) > user_msats THEN | ||
RAISE EXCEPTION 'SN_INSUFFICIENT_FUNDS'; | ||
END IF; | ||
|
||
IF EXISTS (SELECT 1 FROM "Withdrawl" WHERE hash = lnd_id AND status IS NULL) THEN | ||
RAISE EXCEPTION 'SN_PENDING_WITHDRAWL_EXISTS'; | ||
END IF; | ||
|
||
IF EXISTS (SELECT 1 FROM "Withdrawl" WHERE hash = lnd_id AND status = 'CONFIRMED') THEN | ||
RAISE EXCEPTION 'SN_CONFIRMED_WITHDRAWL_EXISTS'; | ||
END IF; | ||
|
||
INSERT INTO "Withdrawl" (hash, bolt11, "msatsPaying", "msatsFeePaying", "userId", created_at, updated_at) | ||
VALUES (lnd_id, invoice, msats_amount, msats_max_fee, user_id, now_utc(), now_utc()) RETURNING * INTO withdrawl; | ||
|
||
UPDATE users SET msats = msats - msats_amount - msats_max_fee WHERE id = user_id; | ||
|
||
RETURN withdrawl; | ||
END; | ||
$$; | ||
|
||
CREATE OR REPLACE FUNCTION check_invoices_and_withdrawals() | ||
RETURNS INTEGER | ||
LANGUAGE plpgsql | ||
AS $$ | ||
DECLARE | ||
BEGIN | ||
INSERT INTO pgboss.schedule (name, cron, timezone) VALUES ('checkPendingDeposits', '*/10 * * * *', 'America/Chicago') ON CONFLICT DO NOTHING; | ||
INSERT INTO pgboss.schedule (name, cron, timezone) VALUES ('checkPendingWithdrawals', '*/10 * * * *', 'America/Chicago') ON CONFLICT DO NOTHING; | ||
return 0; | ||
EXCEPTION WHEN OTHERS THEN | ||
return 0; | ||
END; | ||
$$; | ||
|
||
SELECT check_invoices_and_withdrawals(); | ||
DROP FUNCTION check_invoices_and_withdrawals(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
2 comments
on commit 2151323
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The database will never register that a HODL invoice was paid while the worker was down if there is no check for is_held
in checkInvoice
.
To reproduce:
- Create hodl invoice
- Stop worker
- Pay invoice
- Start worker
- Payment stuck until
finalizeHodlInvoice
gets called
Patch:
diff --git a/worker/wallet.js b/worker/wallet.js
index 816f9ab..7041cd0 100644
--- a/worker/wallet.js
+++ b/worker/wallet.js
@@ -123,6 +123,16 @@ async function checkInvoice ({ data: { hash }, boss, models, lnd }) {
return await boss.send('nip57', { hash })
}
+ if (inv.is_held) {
+ return await models.invoice.update({
+ where: { hash },
+ data: {
+ msatsReceived: Number(inv.received_mtokens),
+ isHeld: true
+ }
+ })
+ }
+
if (inv.is_canceled) {
return await serialize(models,
models.invoice.update({
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some comments but other than that, this looks good and cleaner!
I don't think I'll find anything else. Makes all sense to me and easier to follow.
I guess we don't set
confirmedIndex
here since the subscription callback will set it incheckInvoice
anyway? And we don't need it set here?