Commit Graph

893 Commits

Author SHA1 Message Date
Rusty Russell 838400c702
libplugin: handle JSON reply after command freed.
This can happen, and in fact does below in our test_autoclean_once
test where we update the datastore, and return from the cmd.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2022-09-21 21:44:54 -05:00
Rusty Russell 4249c6176a
libplugin: forget pending requests if associated command freed.
This is usually fine, but without this, commando (another branch!) has
a race:

1. A command has multiple parts.
2. We start sending them out.
3. We get a response, which completes the cmd.
4. We go to send the next one out, but it's been freed.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2022-09-21 21:44:54 -05:00
niftynei 52f1938c57
bkpr: migration to delete any duplicate lease_fee entries
Clean up for #5557.

If you've got duplicate 'lease_fee' entries, we delete them!
2022-09-14 14:05:34 -05:00
Rusty Russell 0145e8ecec
Makefile: Revert ba7d4a8f6b (make-schema: don't include tools/fromschema.py in SHASUMS)
1. If the tool changes, you need to regenerate since the output may
   change.

2. This didn't just filter that out, ignored all but the first
   dependency, which made bisecting the bookkeeper plugin a nightmare:
   it didn't regenerate the .po file, causing random crashes.

If we want this, try $(filter-out tools/fromschema.py) instead.  But I
don't think we want that.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2022-09-13 12:29:46 -05:00
niftynei 1a25651182 bkpr-recorder: fatal if there's an error with a database statement
We were silently failing when NULLS FIRST wasn't found on older boxes
(running sqlite3 < v3.30.1)
2022-08-16 12:32:08 -05:00
niftynei 256044081f bkpr: remove duplicate log stmt 2022-08-10 10:30:45 -05:00
niftynei 23cd58402a bkpr: create accounts for zero sat channels
we weren't making records for 'missed' accounts that had a zero balance
at snapshot time (if peer opens channel and is unused)

Fixes: #5502
Reported-By: https://github.com/niftynei/cln-logmaid
2022-08-10 10:30:45 -05:00
niftynei 3fcf60ab7c bkpr: track channel rebalances, display in listincome
Track rebalances, and report income events for them.

Previously `listincome` would report:
	- invoice event, debit, outgoing channel
	- invoice_fee event, debit, outgoing channel
	- invoice event, credit, inbound channel

Now reports:
	- rebalance_fee, debit, outgoing channel
	(same value as invoice_fee above)

Note: only applies on channel events; if a rebalance falls to chain
we'll use the older style of accounting.

Changelog-None
2022-08-09 11:57:18 +09:30
Christian Decker da0b651803 pay: Use safe list traversal when completing suspended payments
When traversing the list we call `command_finished` which modifies the
list we are traversing. This ensures we don't end up advancing in the
list iteration.

Reported-by: Rusty Russell <@rustyrussell>
2022-08-08 11:52:29 -05:00
Christian Decker 65a449e2c3 pay: Remove use-after-free bug
Technically this is a use-after-free since `command_finished` frees
the `cmd` which is also the parent of `p`, so reset it early. All
paths lead to `command_finished` so setting it early is ok.

Reported-by: Rusty Russell <@rustyrussell>
2022-08-08 11:52:29 -05:00
Christian Decker 093933b14d pay: Do not replay results against payments that were not suspended
Suspended payments now have the same groupid as the actual attempt,
this allows us to identify pay calls that were suspended due to us and
terminate only those.

Changelog-Fixed pay: Fixed a crash when `pay` was called multiple times while an attempt was already in progress.
2022-08-08 11:52:29 -05:00
Christian Decker aca9c7d49c pay: Annotate suspended payments with the groupid they mirror
This should prevent us from accidentally completing a payment twice,
when replaying the result of an actual attempt against pay call that
was suspended due to it still being pending.
2022-08-08 11:52:29 -05:00
Christian Decker 2632cddfe4 pay: Fix a memory leak when retrying getroute 2022-08-04 11:14:45 -05:00
niftynei dfa325dc4d bkpr: make unit tests not fail if !HAVE_SQLITE3
We rely on sqlite3 being present to run unit tests for some bookkeeper
tests; here we effectively disable these tests if not available

Fixes report in #4928
Reported-By: @whitslack
2022-08-02 11:52:57 +09:30
Rusty Russell 2971b2af79 bkpr: insert obscure 60s pop references.
The initial snapshots on an already-running lightningd are expected to
be unbalanced, but this shouldn't cause users to long for the green,
green grass of home.

This controls the Art of Noise.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2022-08-01 09:01:08 -07:00
niftynei 3445882ee4 bkpr: use long-uint not size_t for time_t
Reported-By: @endothermicdev
2022-07-31 21:53:05 +09:30
niftynei 4e503f7d0a bkpr/listpeeers: add lease_fees back to funds; separate out in listpeers
First, how we record "our_funds" and then apply pushes vs lease_fees
(for liquidity ad buys/sales) was exactly opposite.

For pushes we were reporting the total funded into the channel, with the
push representing how much we'd later moved to the peer.

For lease_fees we were rerporting the total in the channel, with the
push representing how much was already moved to the peer.

We fix this (from a view perspective) by re-adding lease fees to what's
reported in the channel funding totals. Since this is now new behavior
(for leased channel values), we added new fields so we can take the old
field names thru a deprecation cycle.

We also make it possible to differentiate btw a push and a lease_fee
(before they were all the same), by adding to new fields to `listpeers`:
`fee_paid_msat` and `fee_rcvd_msat`.

This allows us to avoid math in the bookkeeper, instead we just pick
the numbers out directly and record them.

Fixes #5472

Changelog-Added: JSON-RPC: `listpeers` now has a few new fields for `funding` (`remote_funds_msat`, `local_funds_msat`, `fee_paid_msat`, `fee_rcvd_msat`).
Changelog-Deprecated: JSON-RPC: `listpeers`.`funded` fields `local_msat` and `remote_msat` are now deprecated.
2022-07-31 21:53:05 +09:30
William Casarin 10d66c25c4 commando-rune: show warning when creating runes with no restrictions
Changelog-Added: Show warning when creating runes with no restrictions
Signed-off-by: William Casarin <jb55@jb55.com>
2022-07-29 08:46:14 -07:00
niftynei 6e9af1ef3e bkpr: cleanup csv_safe_str 2022-07-28 12:08:18 +09:30
niftynei c83c1521ce memleak: throw away things when we're done with them
memleak was complaining about dangling refs; they were all allocated off
of `cmd` but not technically unreachabe from any in-context memory.

Instead we move things over to tmpctx to clean up (in the paths where
we're going to move the objects out of reach via intermediate RPC call)

ALSO: cleans up unused param in `lookup_invoice_desc`

lightningd-1 2022-07-23T19:17:11.192Z **BROKEN** plugin-bookkeeper: MEMLEAK: 0x1511f68
lightningd-1 2022-07-23T19:17:11.194Z **BROKEN** plugin-bookkeeper:   label=plugins/bkpr/recorder.c:1048:struct account
lightningd-1 2022-07-23T19:17:11.194Z **BROKEN** plugin-bookkeeper:   backtrace:
lightningd-1 2022-07-23T19:17:11.194Z **BROKEN** plugin-bookkeeper:     ccan/ccan/tal/tal.c:442 (tal_alloc_)
lightningd-1 2022-07-23T19:17:11.194Z **BROKEN** plugin-bookkeeper:     plugins/bkpr/recorder.c:1048 (stmt2account)
lightningd-1 2022-07-23T19:17:11.194Z **BROKEN** plugin-bookkeeper:     plugins/bkpr/recorder.c:1109 (find_account)
lightningd-1 2022-07-23T19:17:11.196Z **BROKEN** plugin-bookkeeper:     plugins/bkpr/bookkeeper.c:1606 (parse_and_log_channel_move)
lightningd-1 2022-07-23T19:17:11.197Z **BROKEN** plugin-bookkeeper:     plugins/bkpr/bookkeeper.c:1713 (json_coin_moved)
lightningd-1 2022-07-23T19:17:11.198Z **BROKEN** plugin-bookkeeper:     plugins/libplugin.c:1421 (ld_command_handle)
lightningd-1 2022-07-23T19:17:11.198Z **BROKEN** plugin-bookkeeper:     plugins/libplugin.c:1491 (ld_read_json_one)
lightningd-1 2022-07-23T19:17:11.199Z **BROKEN** plugin-bookkeeper:     plugins/libplugin.c:1511 (ld_read_json)
lightningd-1 2022-07-23T19:17:11.199Z **BROKEN** plugin-bookkeeper:     ccan/ccan/io/io.c:59 (next_plan)
lightningd-1 2022-07-23T19:17:11.199Z **BROKEN** plugin-bookkeeper:     ccan/ccan/io/io.c:407 (do_plan)
lightningd-1 2022-07-23T19:17:11.199Z **BROKEN** plugin-bookkeeper:     ccan/ccan/io/io.c:417 (io_ready)
lightningd-1 2022-07-23T19:17:11.199Z **BROKEN** plugin-bookkeeper:     ccan/ccan/io/poll.c:453 (io_loop)
lightningd-1 2022-07-23T19:17:11.199Z **BROKEN** plugin-bookkeeper:     plugins/libplugin.c:1708 (plugin_main)
lightningd-1 2022-07-23T19:17:11.199Z **BROKEN** plugin-bookkeeper:     plugins/bkpr/bookkeeper.c:1812 (main)
lightningd-1 2022-07-23T19:17:11.200Z **BROKEN** plugin-bookkeeper:     ../csu/libc-start.c:308 (__libc_start_main)
lightningd-1 2022-07-23T19:17:11.200Z **BROKEN** plugin-bookkeeper:   parents:
lightningd-1 2022-07-23T19:17:11.200Z **BROKEN** plugin-bookkeeper:     plugins/libplugin.c:1378:struct command
lightningd-1 2022-07-23T19:17:11.200Z **BROKEN** plugin-bookkeeper: MEMLEAK: 0x15305b8
lightningd-1 2022-07-23T19:17:11.200Z **BROKEN** plugin-bookkeeper:   label=plugins/bkpr/bookkeeper.c:1643:enum mvt_tag[]
lightningd-1 2022-07-23T19:17:11.200Z **BROKEN** plugin-bookkeeper:   backtrace:
lightningd-1 2022-07-23T19:17:11.200Z **BROKEN** plugin-bookkeeper:     ccan/ccan/tal/tal.c:442 (tal_alloc_)
lightningd-1 2022-07-23T19:17:11.201Z **BROKEN** plugin-bookkeeper:     ccan/ccan/tal/tal.c:471 (tal_alloc_arr_)
lightningd-1 2022-07-23T19:17:11.201Z **BROKEN** plugin-bookkeeper:     plugins/bkpr/bookkeeper.c:1643 (parse_tags)
lightningd-1 2022-07-23T19:17:11.201Z **BROKEN** plugin-bookkeeper:     plugins/bkpr/bookkeeper.c:1686 (json_coin_moved)
lightningd-1 2022-07-23T19:17:11.201Z **BROKEN** plugin-bookkeeper:     plugins/libplugin.c:1421 (ld_command_handle)
lightningd-1 2022-07-23T19:17:11.201Z **BROKEN** plugin-bookkeeper:     plugins/libplugin.c:1491 (ld_read_json_one)
lightningd-1 2022-07-23T19:17:11.201Z **BROKEN** plugin-bookkeeper:     plugins/libplugin.c:1511 (ld_read_json)
lightningd-1 2022-07-23T19:17:11.201Z **BROKEN** plugin-bookkeeper:     ccan/ccan/io/io.c:59 (next_plan)
lightningd-1 2022-07-23T19:17:11.201Z **BROKEN** plugin-bookkeeper:     ccan/ccan/io/io.c:407 (do_plan)
lightningd-1 2022-07-23T19:17:11.202Z **BROKEN** plugin-bookkeeper:     ccan/ccan/io/io.c:417 (io_ready)
lightningd-1 2022-07-23T19:17:11.202Z **BROKEN** plugin-bookkeeper:     ccan/ccan/io/poll.c:453 (io_loop)
lightningd-1 2022-07-23T19:17:11.202Z **BROKEN** plugin-bookkeeper:     plugins/libplugin.c:1708 (plugin_main)
lightningd-1 2022-07-23T19:17:11.203Z **BROKEN** plugin-bookkeeper:     plugins/bkpr/bookkeeper.c:1812 (main)
lightningd-1 2022-07-23T19:17:11.204Z **BROKEN** plugin-bookkeeper:     ../csu/libc-start.c:308 (__libc_start_main)
lightningd-1 2022-07-23T19:17:11.204Z **BROKEN** plugin-bookkeeper:   parents:
lightningd-1 2022-07-23T19:17:11.204Z **BROKEN** plugin-bookkeeper:     plugins/libplugin.c:1378:struct command
lightningd-1 2022-07-23T19:17:11.204Z **BROKEN** plugin-bookkeeper: MEMLEAK: 0x1508da8
lightningd-1 2022-07-23T19:17:11.204Z **BROKEN** plugin-bookkeeper:   label=plugins/bkpr/bookkeeper.c:1568:struct channel_event
lightningd-1 2022-07-23T19:17:11.204Z **BROKEN** plugin-bookkeeper:   backtrace:
lightningd-1 2022-07-23T19:17:11.204Z **BROKEN** plugin-bookkeeper:     ccan/ccan/tal/tal.c:442 (tal_alloc_)
lightningd-1 2022-07-23T19:17:11.204Z **BROKEN** plugin-bookkeeper:     plugins/bkpr/bookkeeper.c:1568 (parse_and_log_channel_move)
lightningd-1 2022-07-23T19:17:11.204Z **BROKEN** plugin-bookkeeper:     plugins/bkpr/bookkeeper.c:1713 (json_coin_moved)
lightningd-1 2022-07-23T19:17:11.205Z **BROKEN** plugin-bookkeeper:     plugins/libplugin.c:1421 (ld_command_handle)
lightningd-1 2022-07-23T19:17:11.205Z **BROKEN** plugin-bookkeeper:     plugins/libplugin.c:1491 (ld_read_json_one)
lightningd-1 2022-07-23T19:17:11.205Z **BROKEN** plugin-bookkeeper:     plugins/libplugin.c:1511 (ld_read_json)
lightningd-1 2022-07-23T19:17:11.205Z **BROKEN** plugin-bookkeeper:     ccan/ccan/io/io.c:59 (next_plan)
lightningd-1 2022-07-23T19:17:11.205Z **BROKEN** plugin-bookkeeper:     ccan/ccan/io/io.c:407 (do_plan)
lightningd-1 2022-07-23T19:17:11.205Z **BROKEN** plugin-bookkeeper:     ccan/ccan/io/io.c:417 (io_ready)
lightningd-1 2022-07-23T19:17:11.205Z **BROKEN** plugin-bookkeeper:     ccan/ccan/io/poll.c:453 (io_loop)
lightningd-1 2022-07-23T19:17:11.205Z **BROKEN** plugin-bookkeeper:     plugins/libplugin.c:1708 (plugin_main)
lightningd-1 2022-07-23T19:17:11.205Z **BROKEN** plugin-bookkeeper:     plugins/bkpr/bookkeeper.c:1812 (main)
lightningd-1 2022-07-23T19:17:11.206Z **BROKEN** plugin-bookkeeper:     ../csu/libc-start.c:308 (__libc_start_main)
lightningd-1 2022-07-23T19:17:11.206Z **BROKEN** plugin-bookkeeper:   parents:
lightningd-1 2022-07-23T19:17:11.206Z **BROKEN** plugin-bookkeeper:     plugins/libplugin.c:1378:struct command
2022-07-28 12:08:18 +09:30
niftynei 2f72bbbbc5 nit: send_outreq returns &pending, no need to call sep command 2022-07-28 12:08:18 +09:30
niftynei e048292fdf bkpr-zeroconf: Zeroconfs will emit 'channel_proposed' event
Keep the accounts as an 'append only' log, instead we move the marker
for the 'channel_open' forward when a 'channel_open' comes out.

We also neatly hide the 'channel_proposed' events in 'inspect' if
there's a 'channel_open' for that same event.

If you call inspect before the 'channel_open' is confirmed, you'll see
the tag as 'channel_proposed', afterwards it shows up as
'channel_open'. However the event log rolls forward -- listaccountevents
will show the correct history of the proposal then open confirming (plus
any routing that happened before the channel confirmed).
2022-07-28 12:08:18 +09:30
niftynei 30aa1d79fb bkpr: for zerconfs, we still wanna know you're opening a channel
We need a record of the channel account before you start sending
payments through it. Normally we don't start allowing payments to be
sent until after the channel has locked in but zeroconf does away with
this assumption.

Instead we push out a "channel_proposed" event, which should only show
up for zeroconfs.
2022-07-28 12:08:18 +09:30
Rusty Russell 305a238810 plugins/Makefile: put bitcoin/chainparams.o in PLUGIN_COMMON_OBJS since everyone needs it.
This was originally done as part of the bookkeeper introduction, but it deserves its
own patch (and that one didn't remove the bitcoin/chainparams.o from the individual
requirements lines).

Suggested-by: @niftynei
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2022-07-28 12:08:18 +09:30
niftynei 71c03bc082 bkpr: Add an option to set the database to something else (postgres)
`lightningd` has an option --wallet that lets you supply a database dsn
string to connect to a sqlite3/postgres database that's hosted/stored
elsewhere.

This adds the `--bookkeeper-db` option which does the same, except for
the bookkeeping data for a node!

Note that the default is to go in the `lightning-dir` in a database
called `accounts.sqlite3`
2022-07-28 12:08:18 +09:30
niftynei e5d3ce3b1f bkpr incomestmt: properly escape things for the CSVs
First off, when we pull data out of JSON, unescape it so we don't end up
with extraneous escapes in our bookkeeping data. I promise, it's worth
it.

Then, when we print descriptions out to the csvs, we gotta wrap
everything in quotes... but also we have to change all the double-quotes
to singles so that adding the quotes doesn't do anything untoward.

We also just pass it thru json_escape to get rid of linebreaks etc.

Note that in the tests we do a byte comparison instead of converting the
CSV dumps to strings because python will escape the strings on
conversion...
2022-07-28 12:08:18 +09:30
niftynei 5146baa00b bkpr csvs: koinly + cointracker only accept fees on the same line
So we print out invoice fees on the same line for those CSVs! This means
we have to do a little bit of gymnastics (but not too bad):
	- we save the fee amount onto the income event now so we can use
it later
	- we ignore every "invoice_fee" event for the koinly/cointracker

Note that since we're not skipping income events in the loops we also
move the newline character to the start of every `_entry` function so
skipped records dont incur empth lines.

Changelog-Added: bkpr: print out invoice fees on the same line for `koinly` and `cointracker` csv types
2022-07-28 12:08:18 +09:30
niftynei 352b419755 bkpr: save invoice description data to the database and display it
It'll be really nice to be able to read description data about an
invoice, if we've got it!
2022-07-28 12:08:18 +09:30
niftynei 2d22bab879 bkpr: fetch originating account, if exists, and make sure is populated
It's possible we'll get an "external" event for an account/channel and
then try to do close checks on it and it'll bomb out because we didn't
go look up the originating account to make sure that that had open info

Now, we make sure and do that when we hear about an originating account
2022-07-28 12:08:18 +09:30
niftynei 55e15c5f10 bkpr: correctly pass in command for `jsonrpc_request_start`
We weren't passing the command, which meant that it wasn't getting
populated correctly.

We do that now, it fixes some crashes
2022-07-28 12:08:18 +09:30
niftynei 67ce0ee3b2 bkpr: prevent crash when updating same account all at once
If two events for the same (unlogged) account come in and get run
through the "lookup peer" code, we should anticipate that.

We do two things here:
	- one, if it's a duplicate "event" to create the channel open
	  we check for that and just exit early
	- two, we were using a copy of the account that was
	  fetched/pulled from before the RPC ran, so instead we
	  just re-pull the most up to date account info for the
	  close checks.

This fixes the crash I was getting in re-running these things
2022-07-28 12:08:18 +09:30
niftynei 38eb95ffee bkpr: more logging 2022-07-28 12:08:18 +09:30
niftynei 9346158290 bkpr: new method, "is_external_account"
Utility method to figure out if an account is "external"
2022-07-28 12:08:18 +09:30
niftynei 97204d6e0a bkpr: duplicate the name, dont steal it 2022-07-28 12:08:18 +09:30
niftynei 0617690981 coin_mvt/bkpr: add "stealable" tag to stealable outputs
If we expect further events for an onchain output (because we can steal
it away from the 'external'/rightful owner), we mark them.

This prevents us from marking a channel as 'onchain-resolved' before
all events that we're interested in have actually hit the chain.

Case that this matters:
Peer publishes a (cheating) unilateral close and a timeout htlc (which
we can steal).
We then steal the timeout htlc.

W/o the stealable flag, we'd have marked the channel as resolved when
the peer published the timeout htlc, which is incorrect as we're still
waiting for the resolution of that timeout htlc (b/c we *can* steal it).
2022-07-28 12:08:18 +09:30
niftynei c1cef773ca bkpr: make sure there's always at least on difference in blockheights
We can't divide by zero, so make sure it's always 1 (with a small loss
of precision for other cases, ce la vie)
2022-07-28 12:08:18 +09:30
niftynei 0c2b43b6b2 bkpr: add more data to listaccountevents printout 2022-07-28 12:08:18 +09:30
niftynei d72033882f bkpr: check for channel resolution for any "originated" event
We were failing to mark channels as resolved b/c we weren't using later
events to external (but originated from this account) events as signals
to run the channel resolution check.

This fixes that, and adds a test.
2022-07-28 12:08:18 +09:30
niftynei cf8b30d2e8 bkpr: print more info in bkpr-listbalances 2022-07-28 12:08:18 +09:30
niftynei 3dcfd2d0e4 bkpr: account name is required for bkpr-inspect 2022-07-28 12:08:18 +09:30
niftynei 563910e667 bkpr: add docs, change names to 'bkpr-*'
Adds schema definitions and manpages for bkpr- commands; also renames
the commands to all start with 'bkpr-', so they're easier to identify/
make runes about.
2022-07-28 12:08:18 +09:30
niftynei e2ef44c043 bkpr: add 'msat' suffix to all msat denominated fields
Makes our json schema parsing work as expected.
2022-07-28 12:08:18 +09:30
niftynei 2b3ef37590 bkpr: don't use a minus in a sql stmt
Avoid rounding errors in sql by doing it in code.
2022-07-28 12:08:18 +09:30
niftynei a45da63280 bkpr: pass the node_id over for channel_opens, add to account
it's nice to know what node your channel was opened with. in theory we
could use listpeers to merge the data after the fact, except that
channels disappear after they've been closed for a bit. it's better to
just save the info.

we print it out in `listbalances`, as that's a great place account level
information
2022-07-28 12:08:18 +09:30
niftynei a3d82d5a01 bkpr: exclude non-wallet events in the balance snapshot
Anchor outputs are ignored by the clightning wallet, but we keep track
of them in the bookkeeper. This causes problems when we do the balance
checks on restart w/ the balance_snapshot -- it results in us printing
out a journal_entry to 'get rid of' the anchors that the clightning node
doesnt know about.

Instead, we mark some outputs as 'ignored' and exclude these from our
account balance sums when we're comparing to the clightning snapshot.
2022-07-28 12:08:18 +09:30
niftynei fec8186413 bkpr: get rid of crash in `listincome`
Our consolidate fees had a crash bug (and was pretty convoluted). This
makes it less convoluted and resolves the crash.

The only kinda meh thing is that we have to look up the most recent
timestamp data for the onchain fee entry separately, because of the way
SQL sums work.
2022-07-28 12:08:18 +09:30
niftynei 10e58a3788 nit,bkpr: add a note about what the tag was to this printout
Makes it much easier to debug when something goes wrong!
2022-07-28 12:08:18 +09:30
niftynei e7ed196f87 bkpr: separate the invoice_fees from the invoice paid
For income events, break out the amount paid in routing fees vs the
total amount of the *invoice* that is paid.

Also printout these fees, when available, on listaccountevents
2022-07-28 12:08:18 +09:30
niftynei 91ebddeb78 bkpr: actually fill in the current blockheight for `channelsapy`
I had hardcoded something for the tests, but really we want this to be
dynamically fetched from lightningd via `getinfo`.

This does the trick!
2022-07-28 12:08:18 +09:30
niftynei ee47715a1b bkpr: command to calculate some APYs/stats on channel routing fees
Computes some stats from the net routed fees etc

```
{
   "channel_apys": [
      {
         "account": "7de277250f8003c35378c1eb20aacf8fa6a69dd4bb22077266329a9ad812cd5d",
         "routed_out": "2000msat",
         "routed_in": "125100101msat",
         "lease_fee_paid": "0msat",
         "lease_fee_earned": "670000msat",
         "pushed_out": "0msat",
         "pushed_in": "0msat",
         "our_start_balance": "100670000msat",
         "channel_start_balance": "1100670000msat",
         "fees_out": "0msat",
         "fees_in": "10100101msat",
         "utilization_out": "0.0002%",
         "utilization_out_initial": "0.0020%",
         "utilization_in": "11.3658%",
         "utilization_in_initial": "12.5100%",
         "apy_out": "0.0000%",
         "apy_out_initial": "0.0000%",
         "apy_in": "3203.3924%",
         "apy_in_initial": "3525.8779%",
         "apy_total": "3203.3924%",
         "apy_total_initial": "3203.3924%",
         "apy_lease": "8.7014%"
      },
      {
         "account": "b71937a02eb7694d946c311297ca2da454057c5c3e97ac67500739cc2afbc0c5",
         "routed_out": "110000000msat",
         "routed_in": "0msat",
         "lease_fee_paid": "670000msat",
         "lease_fee_earned": "0msat",
         "pushed_out": "0msat",
         "pushed_in": "0msat",
         "our_start_balance": "4000000000msat",
         "channel_start_balance": "4100670000msat",
         "fees_out": "10100101msat",
         "fees_in": "0msat",
         "utilization_out": "2.6825%",
         "utilization_out_initial": "2.7500%",
         "utilization_in": "0.0000%",
         "utilization_in_initial": "0.0000%",
         "apy_out": "2579.4892%",
         "apy_out_initial": "2644.4084%",
         "apy_in": "0.0000%",
         "apy_in_initial": "0.0000%",
         "apy_total": "2579.4892%",
         "apy_total_initial": "2579.4892%"
      },
      {
         "account": "net",
         "routed_out": "110002000msat",
         "routed_in": "125100101msat",
         "lease_fee_paid": "670000msat",
         "lease_fee_earned": "670000msat",
         "pushed_out": "0msat",
         "pushed_in": "0msat",
         "our_start_balance": "4100670000msat",
         "channel_start_balance": "5201340000msat",
         "fees_out": "10100101msat",
         "fees_in": "10100101msat",
         "utilization_out": "2.1149%",
         "utilization_out_initial": "2.6825%",
         "utilization_in": "2.4052%",
         "utilization_in_initial": "11.3658%",
         "apy_out": "677.8788%",
         "apy_out_initial": "859.8297%",
         "apy_in": "677.8788%",
         "apy_in_initial": "3203.3924%",
         "apy_total": "1355.7575%",
         "apy_total_initial": "1355.7575%",
         "apy_lease": "0.2122%"
      }
   ]
}
```
2022-07-28 12:08:18 +09:30