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
Exemple #2
0
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