FIX: properly locked payments

This commit is contained in:
Overtorment 2019-03-03 15:59:30 +00:00
parent afb07aa9ba
commit 8f2d98774b
4 changed files with 71 additions and 2 deletions

View File

@ -2,14 +2,15 @@ var crypto = require('crypto');
var lightningPayReq = require('bolt11');
import { BigNumber } from 'bignumber.js';
export class Paym {
export class Payment {
constructor(redis, bitcoindrpc, lightning) {
this._redis = redis;
this._bitcoindrpc = bitcoindrpc;
this._lightning = lightning;
this._decoded = false;
}
async decodePayReq(invoice) {
async decodePayReqViaRpc(invoice) {
return new Promise(function(resolve, reject) {
this._lightning.decodePayReq({ pay_req: invoice }, function(err, info) {
if (err) return reject(err);
@ -17,4 +18,8 @@ export class Paym {
});
});
}
decodePayReq(payReq) {
this._decoded = lightningPayReq.decode(payReq);
}
}

View File

@ -153,6 +153,13 @@ export class User {
calculatedBalance -= +tx.value;
}
}
let lockedPayments = await this.getLockedPayments();
for (let paym of lockedPayments) {
// TODO: check if payment in determined state and actually evict it from this list
calculatedBalance -= +paym.amount;
}
return calculatedBalance;
}
@ -386,6 +393,59 @@ export class User {
}
}
/**
* Adds invoice to a list of user's locked payments.
* Used to calculate balance till the lock is lifted (payment is in
* determined state - succeded or failed).
*
* @param {String} pay_req
* @param {Object} decodedInvoice
* @returns {Promise<void>}
*/
async lockFunds(pay_req, decodedInvoice) {
let doc = {
pay_req,
amount: +decodedInvoice.num_satoshis,
timestamp: Math.floor(+new Date() / 1000),
};
return this._redis.rpush('locked_payments_for_' + this._userid, JSON.stringify(doc));
}
/**
* Strips specific payreq from the list of locked payments
* @param pay_req
* @returns {Promise<void>}
*/
async unlockFunds(pay_req) {
let payments = await this.getLockedPayments();
let saveBack = [];
for (let paym of payments) {
if (paym.pay_req !== pay_req) {
saveBack.push(paym);
}
}
await this._redis.del('locked_payments_for_' + this._userid);
for (let doc of saveBack) {
await this._redis.rpush('locked_payments_for_' + this._userid, JSON.stringify(doc));
}
}
async getLockedPayments() {
let payments = await this._redis.lrange('locked_payments_for_' + this._userid, 0, -1);
let result = [];
for (let paym of payments) {
let json;
try {
json = JSON.parse(paym);
result.push(json);
} catch (_) {}
}
return result;
}
_hash(string) {
return crypto
.createHash('sha256')

View File

@ -185,6 +185,7 @@ router.post('/payinvoice', async function(req, res) {
var call = lightning.sendPayment();
call.on('data', async function(payment) {
// payment callback
await u.unlockFunds(req.body.invoice);
if (payment && payment.payment_route && payment.payment_route.total_amt_msat) {
userBalance -= +payment.payment_route.total_fees + +payment.payment_route.total_amt;
u.saveBalance(userBalance);
@ -206,6 +207,7 @@ router.post('/payinvoice', async function(req, res) {
}
let inv = { payment_request: req.body.invoice, amt: info.num_satoshis }; // amt is used only for 'tip' invoices
try {
await u.lockFunds(req.body.invoice, info);
call.write(inv);
} catch (Err) {
await lock.releaseLock();

View File

@ -20,6 +20,8 @@ User storage schema
* bitcoin_address_for_{userid} = {address}
* balance_for_{userid} = {int}
* txs_for_{userid} = [] `serialized paid lnd invoices in a list`
* locked_invoices_for_{userod} = [] `serialized attempts to pay invoice. used in calculating user's balance`
: {pay_req:..., amount:666, timestamp:666}
* imported_txids_for_{userid} = [] `list of txids processed for this user`
* metadata_for_{userid}= {serialized json}
* userinvoices_for_{userid} = []