UNPKG

ln-sync

Version:
313 lines (281 loc) 10.9 kB
const asyncAuto = require('async/auto'); const {getChannels} = require('lightning/lnd_methods'); const {getWalletInfo} = require('lightning/lnd_methods'); const {returnResult} = require('asyncjs-util'); const keyForRecord = require('./key_for_record'); const localChannelUpdate = require('./local_channel_update'); const add = 1; const createRecordRev = 0; const fresh = ['id']; const hexAsBuffer = hex => Buffer.from(hex, 'hex'); const idSeparator = ':'; const table = 'local_channels'; const type = 'local_channel'; /** Sync local channel details { db: { getItem: <Get Item Function> putItem: <Put Item Function> updateItem: <Update Item Function> } lnd: <Authenticated LND API Object> public_key: <Public Key Hex String> transaction_id: <Funding Transaction Id String> transaction_vout: <Funding Transaction Vout Number> } @returns via cbk or Promise { [created]: { capacity: <Channel Token Capacity Number> commit_transaction_fee: <Commit Transaction Fee Number> commit_transaction_weight: <Commit Transaction Weight Number> [cooperative_close_address]: <Coop Close Restricted to Address String> id: <Standard Format Channel Id String> is_active: <Channel Active Bool> is_partner_initiated: <Channel Partner Opened Channel Bool> is_private: <Channel Is Private Bool> [is_static_remote_key]: <Remote Key Is Static Bool> local_balance: <Local Balance Tokens Number> [local_given]: <Local Initially Pushed Tokens Number> local_reserve: <Local Reserved Tokens Number> partner_public_key: <Channel Partner Public Key Buffer Object> received: <Received Tokens Number> remote_balance: <Remote Balance Tokens Number> [remote_given]: <Remote Initially Pushed Tokens Number> remote_reserve: <Remote Reserved Tokens Number> sent: <Sent Tokens Number> transaction_id: <Blockchain Transaction Id String> transaction_vout: <Blockchain Transaction Vout Number> unsettled_balance: <Unsettled Balance Tokens Number> } [original]: { id: <Standard Format Channel Id String> } [previous]: { [commit_transaction_fee]: <Commitment Transaction Fee Tokens Number> [commit_transaction_weight]: <Commitment Transaction Weight Units Number> [is_active]: <Channel Is Active Bool> [local_balance]: <Channel Local Balance Tokens Number> [received]: <Channel Received Tokens Number> [remote_balance]: <Channel Remote Balance Tokens Number> [sent]: <Channel Sent Tokens Number> [unsettled_balance]: <Channel Unsettled Tokens Number> } [updates]: { [commit_transaction_fee]: <Commitment Transaction Fee Tokens Number> [commit_transaction_weight]: <Commitment Transaction Weight Units Number> [is_active]: <Channel Is Active Bool> [local_balance]: <Channel Local Balance Tokens Number> [received]: <Channel Received Tokens Number> [remote_balance]: <Channel Remote Balance Tokens Number> [sent]: <Channel Sent Tokens Number> [unsettled_balance]: <Channel Unsettled Tokens Number> } } */ module.exports = (args, cbk) => { return new Promise((resolve, reject) => { return asyncAuto({ // Check arguments validate: cbk => { if (!args.db) { return cbk([400, 'ExpectedDatabaseToSyncLocalChannel']); } if (!args.lnd) { return cbk([400, 'ExpectedLndToSyncLocalChannel']); } if (!args.public_key) { return cbk([400, 'ExpectedPublicKeyToSyncLocalChannel']); } if (!args.transaction_id) { return cbk([400, 'ExpectedFundingTransactionIdToSyncLocalChannel']); } if (args.transaction_vout === undefined) { return cbk([400, 'ExpectedTransactionOutputToSyncLocalChannel']); } return cbk(); }, // Derive the key for the row key: ['validate', ({}, cbk) => { const id = [ args.public_key, args.transaction_id, args.transaction_vout, ]; return cbk(null, keyForRecord({type, id: id.join(idSeparator)}).key); }], // Get the stored record getStored: ['key', ({key}, cbk) => args.db.getItem({key, table}, cbk)], // Get the fresh data getFresh: ['getStored', ({getStored}, cbk) => { // There is no local channel lookup method, so get all return getChannels({lnd: args.lnd}, (err, res) => { if (!!err) { return cbk(err); } const channel = res.channels .filter(n => n.transaction_id === args.transaction_id) .find(n => n.transaction_vout === args.transaction_vout); return cbk(null, channel); }); }], // Determine creation of the record create: ['getFresh', 'getStored', ({getFresh, getStored}, cbk) => { // Exit early when the record is already present or there is no fresh if (!getFresh || !!getStored.record) { return cbk(); } const record = { _rev: createRecordRev, capacity: getFresh.capacity, commit_transaction_fee: getFresh.commit_transaction_fee, commit_transaction_weight: getFresh.commit_transaction_weight, cooperative_close_address: getFresh.cooperative_close_address, id: getFresh.id, is_active: getFresh.is_active, is_partner_initiated: getFresh.is_partner_initiated, is_private: getFresh.is_private, is_static_remote_key: getFresh.is_static_remote_key, local_balance: getFresh.local_balance, local_given: getFresh.local_given, local_public_key: hexAsBuffer(args.public_key), local_reserve: getFresh.local_reserve, partner_public_key: hexAsBuffer(getFresh.partner_public_key), received: getFresh.received, remote_balance: getFresh.remote_balance, remote_given: getFresh.remote_given, remote_reserve: getFresh.remote_reserve, sent: getFresh.sent, transaction_id: hexAsBuffer(args.transaction_id), transaction_vout: args.transaction_vout, unsettled_balance: getFresh.unsettled_balance, }; return cbk(null, record); }], // Determine update update: [ 'getFresh', 'getStored', 'key', ({getFresh, getStored, key}, cbk) => { const {record} = getStored; // Exit early when there is no stored record if (!getFresh || !record) { return cbk(); } try { const update = localChannelUpdate({ record, channel: { commit_transaction_fee: getFresh.commit_transaction_fee, commit_transaction_weight: getFresh.commit_transaction_weight, is_active: getFresh.is_active, local_balance: getFresh.local_balance, received: getFresh.received, remote_balance: getFresh.remote_balance, sent: getFresh.sent, unsettled_balance: getFresh.unsettled_balance, }, }); return cbk(null, update); } catch (err) { return cbk([503, 'UnexpectedErrorDerivingChannelUpdate', {err}]); } }], // Execute the create to the database executeCreate: ['create', 'key', ({create, key}, cbk) => { // Exit early when there is no create to execute if (!create) { return cbk(); } return args.db.putItem({fresh, key, table, record: create}, cbk); }], // Execute the update on the database executeUpdate: [ 'getStored', 'key', 'update', ({getStored, key, update}, cbk) => { // Exit early when there is nothing to update if (!update || !update.changes) { return cbk(); } return args.db.updateItem({ key, table, changes: update.changes, expect: {_rev: getStored.record._rev}, }, cbk); }], // Result of update updates: [ 'create', 'getStored', 'update', ({create, getStored, update}, cbk) => { if (!!update && !!update.changes) { const {previous} = update; const {updates} = update; return cbk(null, { original: { id: getStored.record.id, }, previous: { commit_transaction_fee: previous.commit_transaction_fee, commit_transaction_weight: previous.commit_transaction_weight, is_active: previous.is_active, local_balance: previous.local_balance, received: previous.received, remote_balance: previous.remote_balance, sent: previous.sent, unsettled_balance: previous.unsettled_balance, }, updates: { commit_transaction_fee: updates.commit_transaction_fee, commit_transaction_weight: updates.commit_transaction_weight, is_active: updates.is_active, local_balance: updates.local_balance, received: updates.received, remote_balance: updates.remote_balance, sent: updates.sent, unsettled_balance: updates.unsettled_balance, }, }); } if (!!create) { return cbk(null, { created: { capacity: create.capacity, commit_transaction_fee: create.commit_transaction_fee, commit_transaction_weight: create.commit_transaction_weight, cooperative_close_address: create.cooperative_close_address, id: create.id, is_active: create.is_active, is_partner_initiated: create.is_partner_initiated, is_private: create.is_private, is_static_remote_key: create.is_static_remote_key, local_balance: create.local_balance, local_given: create.local_given, local_reserve: create.local_reserve, partner_public_key: create.partner_public_key, received: create.received, remote_balance: create.remote_balance, remote_given: create.remote_given, remote_reserve: create.remote_reserve, sent: create.sent, transaction_id: args.transaction_id, transaction_vout: args.transaction_vout, unsettled_balance: create.unsettled_balance, }, }); } return cbk(null, {}); }], }, returnResult({reject, resolve, of: 'updates'}, cbk)); }); };