Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions src/invoicing.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,17 +255,26 @@ class PurpleInvoiceManager {

// Checks the status of an invoice once. Returns true if paid, false otherwise.
async check_invoice_is_paid(label) {
const params = { label }
const timeout_ms = parseInt(process.env.LN_INVOICE_CHECK_TIMEOUT_MS) || 60000

try {
const params = { label }
return new Promise(async (resolve, reject) => {
setTimeout(() => {
resolve(undefined)
}, parseInt(process.env.LN_INVOICE_CHECK_TIMEOUT_MS) || 60000)
const res = await this.ln_rpc({ method: "waitinvoice", params })
resolve(res.error ? false : true)
})
}
catch {
const res = await Promise.race([
this.ln_rpc({ method: "waitinvoice", params }),
new Promise((resolve) => {
setTimeout(() => {
resolve(undefined)
}, timeout_ms)
})
])

if (res == null) {
return undefined
}

return res.error ? false : true
} catch (e) {
error("Error checking invoice %s: %s", label, e.toString())
return undefined
}
}
Expand Down
46 changes: 46 additions & 0 deletions test/ln_flow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,49 @@ test('LN Flow — Background polling processes paid invoices without client chec

t.end();
});

test('LN Flow — failed LN node connection during check-invoice returns unpaid checkout and server keeps working', async (t) => {
const purple_api_controller = await PurpleTestController.new(t);
const user_pubkey_1 = purple_api_controller.new_client();

const new_checkout_response = await purple_api_controller.clients[user_pubkey_1].new_checkout(PURPLE_ONE_MONTH);
t.same(new_checkout_response.statusCode, 200);

const verify_checkout_response = await purple_api_controller.clients[user_pubkey_1].verify_checkout(new_checkout_response.body.id);
t.same(verify_checkout_response.statusCode, 200);

const originalLNSocket = purple_api_controller.purple_api.invoice_manager.constructor.LNSocket;
purple_api_controller.purple_api.invoice_manager.constructor.LNSocket = async () => ({
genkey() {},
async connect_and_init() {
throw new Error('connect ECONNREFUSED 24.86.66.39:9735');
},
destroy() {}
});

t.teardown(() => {
purple_api_controller.purple_api.invoice_manager.constructor.LNSocket = originalLNSocket;
});

const failedCheckResponse = await purple_api_controller.clients[user_pubkey_1].check_invoice(new_checkout_response.body.id);
t.same(failedCheckResponse.statusCode, 200);
t.same(failedCheckResponse.body.completed, false);
t.same(failedCheckResponse.body.invoice?.paid, undefined);

const checkoutAfterFailure = await purple_api_controller.clients[user_pubkey_1].get_checkout(new_checkout_response.body.id);
t.same(checkoutAfterFailure.statusCode, 200);
t.same(checkoutAfterFailure.body.completed, false);
t.same(checkoutAfterFailure.body.invoice?.paid, undefined);

const accountAfterFailure = await purple_api_controller.clients[user_pubkey_1].get_account();
t.same(accountAfterFailure.statusCode, 404);

const productsResponse = await purple_api_controller.clients[user_pubkey_1].get_products();
t.same(productsResponse.statusCode, 200);
t.ok(productsResponse.body[PURPLE_ONE_MONTH]);

const secondCheckoutResponse = await purple_api_controller.clients[user_pubkey_1].new_checkout(PURPLE_ONE_MONTH);
t.same(secondCheckoutResponse.statusCode, 200);
});


Loading