def receivedinvoiceless(plugin, min_amount: Millisatoshi = Millisatoshi(10000)): """ List payments received via sendinvoiceless from other nodes. """ mynodeid = plugin.rpc.getinfo()['id'] mychannels = plugin.rpc.listchannels(source=mynodeid)['channels'] forwards = plugin.rpc.listforwards()['forwards'] default_fees = { 'base': int(plugin.get_option('fee-base')), 'ppm': int(plugin.get_option('fee-per-satoshi')) } # build a mapping of mychannel fees # <scid -> {base, ppm}> myfees = {} for channel in mychannels: scid = channel['short_channel_id'] myfees[scid] = { 'base': channel['base_fee_millisatoshi'], 'ppm': channel['fee_per_millionth'] } # loop through settled forwards and check for overpaid routings result = [] for forward in forwards: if forward['status'] != "settled": continue # for old channel, we dont know fees anymore, use defaults scid = forward['out_channel'] fees = myfees.get(scid, default_fees) fee_paid = forward['fee'] fee_required = int(forward['out_msatoshi'] * fees['ppm'] * 10**-6 + fees['base']) if fee_paid > fee_required: amount = Millisatoshi(fee_paid - fee_required) # fess can sometimes not be exact when channel fees changed in the past, filter those if amount < min_amount: continue entry = {'amount_msat': amount, 'amount_btc': amount.to_btc_str()} # old lightningd versions may not support received_time yet if 'resolved_time' in forward: time_secs = int(forward['resolved_time']) time_str = datetime.utcfromtimestamp(time_secs).strftime( '%Y-%m-%d %H:%M:%S (UTC)') entry['resolved_time'] = forward['resolved_time'] entry['timestamp'] = time_str result.append(entry) return result
def summary(plugin, exclude=''): """Gets summary information about this node.""" reply = {} info = plugin.rpc.getinfo() funds = plugin.rpc.listfunds() peers = plugin.rpc.listpeers() # Make it stand out if we're not on mainnet. if info['network'] != 'bitcoin': reply['network'] = info['network'].upper() if hasattr(plugin, 'my_address') and plugin.my_address: reply['my_address'] = plugin.my_address else: reply['warning_no_address'] = "NO PUBLIC ADDRESSES" utxos = [int(f['amount_msat']) for f in funds['outputs'] if f['status'] == 'confirmed'] reply['num_utxos'] = len(utxos) utxo_amount = Millisatoshi(sum(utxos)) reply['utxo_amount'] = utxo_amount.to_btc_str() avail_out = Millisatoshi(0) avail_in = Millisatoshi(0) chans = [] reply['num_channels'] = 0 reply['num_connected'] = 0 reply['num_gossipers'] = 0 for p in peers['peers']: pid = p['id'] addpeer(plugin, p) active_channel = False for c in p['channels']: if c['state'] != 'CHANNELD_NORMAL': continue active_channel = True if c['short_channel_id'] in exclude: continue if p['connected']: reply['num_connected'] += 1 if c['our_reserve_msat'] < c['to_us_msat']: to_us = c['to_us_msat'] - c['our_reserve_msat'] else: to_us = Millisatoshi(0) avail_out += to_us # We have to derive amount to them to_them = c['total_msat'] - c['to_us_msat'] if c['their_reserve_msat'] < to_them: to_them = to_them - c['their_reserve_msat'] else: to_them = Millisatoshi(0) avail_in += to_them reply['num_channels'] += 1 chans.append(Channel( c['total_msat'], to_us, to_them, pid, c['private'], p['connected'], c['short_channel_id'], plugin.persist['peerstate'][pid]['avail'] )) if not active_channel and p['connected']: reply['num_gossipers'] += 1 reply['avail_out'] = avail_out.to_btc_str() reply['avail_in'] = avail_in.to_btc_str() if plugin.fiat_per_btc > 0: reply['utxo_amount'] += ' ({})'.format(to_fiatstr(utxo_amount)) reply['avail_out'] += ' ({})'.format(to_fiatstr(avail_out)) reply['avail_in'] += ' ({})'.format(to_fiatstr(avail_in)) if chans != []: reply['channels_flags'] = 'P:private O:offline' reply['channels'] = ["\n"] biggest = max(max(int(c.ours), int(c.theirs)) for c in chans) append_header(reply['channels'], biggest) for c in chans: # Create simple line graph, 47 chars wide. our_len = int(round(int(c.ours) / biggest * 23)) their_len = int(round(int(c.theirs) / biggest * 23)) divided = False # We put midpoint in the middle. mid = draw.mid if our_len == 0: left = "{:>23}".format('') mid = draw.double_left else: left = "{:>23}".format(draw.left + draw.bar * (our_len - 1)) if their_len == 0: right = "{:23}".format('') # Both 0 is a special case. if our_len == 0: mid = draw.empty else: mid = draw.double_right else: right = "{:23}".format(draw.bar * (their_len - 1) + draw.right) s = left + mid + right # output short channel id, so things can be copyNpasted easily s += " {:14} ".format(c.scid) extra = '' if c.private: extra += 'P' else: extra += '_' if not c.connected: extra += 'O' else: extra += '_' s += '[{}] '.format(extra) # append 24hr availability s += '{:4.0%} '.format(c.avail) # append alias or id node = plugin.rpc.listnodes(c.pid)['nodes'] if len(node) != 0 and 'alias' in node[0]: s += node[0]['alias'] else: s += c.pid[0:32] reply['channels'].append(s) # Make modern lightning-cli format this human-readble by default! reply['format-hint'] = 'simple' return reply