Conversation
a6ad47c to
9fe8217
Compare
3b74b16 to
5a99ad9
Compare
rustyrussell
left a comment
There was a problem hiding this comment.
OK, I took a careful look since this is a brand new API. Though to be fair I didn't review all the calling paths in sufficient detail (there are many!).
So mainly minor (though, sorry, invasive) proposals. I really like this idea of a comprehensive API for coin moves, though, and it'd be great to get it in 0.8.2.
lightningd/htlc_end.c
Outdated
| hout->partid = partid; | ||
| else | ||
| hout->partid = 0; | ||
|
|
There was a problem hiding this comment.
I disagree with this: partid should never be accessed if !am_origin. Your API should reflect this, too: don't output partid at all if there's no corresponding payment.
wallet/db.c
Outdated
| {SQL("UPDATE channel_htlcs SET localfailmsg=decode('2002', 'hex') WHERE malformed_onion != 0 AND direction = 1;"), NULL}, | ||
| /* For incoming HTLCs, we now keep track of whether or not we provided | ||
| * the preimage for it, or not. */ | ||
| {SQL("ALTER TABLE channel_htlcs ADD we_filled INT;"), NULL}, |
There was a problem hiding this comment.
I think INTEGER is preferred to INT in SQL, but I note we use both so maybe I'm wrong?
There was a problem hiding this comment.
sqlite3 is very lax with regards to its type-system, they're effectively aliases. In postgres this would be an s32, so we need to make sure that doesn't break.
There was a problem hiding this comment.
this has been addressed. @rustyrussell was there another comment that was overlooked?
| db_bind_int(stmt, 5, 1); | ||
| else | ||
| db_bind_null(stmt, 5); | ||
|
|
There was a problem hiding this comment.
I prefer 0/1 rather than NULL/1? Make we_filled a bool * and then do:
/* Set for htlc_in */
if (we_filled)
db_bind_int(stmt, 5, *we_filled);
else
db_bind_null(stmt, 5);
There was a problem hiding this comment.
this has been updated!
wallet/wallet.c
Outdated
| } | ||
| #endif | ||
|
|
||
| in->we_filled = !db_column_is_null(stmt, 13); |
common/coin_mvt.c
Outdated
| return mvt_units[unit]; | ||
| } | ||
|
|
||
| static u64 mvt_count = 0; |
There was a problem hiding this comment.
This surely belongs in a db somewhere?
wire/towire.c
Outdated
| if (tx->input_amounts[i]) | ||
| towire_amount_sat(pptr, *tx->input_amounts[i]); | ||
| else | ||
| towire_amount_sat(pptr, AMOUNT_SAT(0)); |
There was a problem hiding this comment.
You can have zero-valued inputs though. I think we should do all or nothing: either assert() that all input_amounts are set if tx->input_amounts is non-NULL, or don't include any if we don't have all of them.
onchaind/onchaind.c
Outdated
| bool option_static_remotekey; | ||
|
|
||
| /* We don't want to log any downstream coin moves if this is a known replay */ | ||
| bool open_is_replay; |
There was a problem hiding this comment.
This should be "initial_tx_is_replay" perhaps? open is confusing here...
There was a problem hiding this comment.
updated in 6c8d7ef to be pass through instead of a global (having a global didn't get me much of anything).
lightningd/coin_mvts.c
Outdated
| /* This could be written more concisely as | ||
| * count = ++ld->coin_moves_count; | ||
| * however I believe that's contra-code conventions */ | ||
| ld->coin_moves_count++; | ||
| count = ld->coin_moves_count; | ||
| db_set_intvar(ld->wallet->db, "coin_moves_count", | ||
| count); |
There was a problem hiding this comment.
No, I have no problem with ++ prefix when necessary (it's just that C++ programmers have been trained to use it by default). I'd just do this all as a one-liner...
lightningd/coin_mvts.c
Outdated
| { | ||
| s64 count; | ||
| bool db_in_tx; | ||
| db_in_tx = db_in_transaction(ld->wallet->db); |
There was a problem hiding this comment.
I'm curious about what callchains do this outside a transaction? That has a weird smell to it...
There was a problem hiding this comment.
Hm I can't seem to find them. I'm going to push the non-switched version up and see if Travis can find them for me :)
lightningd/coin_mvts.c
Outdated
| "coin_moves_count", -1); | ||
| db_commit_transaction(ld->wallet->db); | ||
| if (count == -1) | ||
| fatal("Something went wrong attmepting to fetch" |
There was a problem hiding this comment.
typo, but maybe it's not? :)
|
Didn't get too far with It results in
In this configuration |
|
The other configuration is the following: Surprisingly little errors despite the chain being different. It also produces the above |
9a19635 to
9a6f307
Compare
20dfc7b to
4b47525
Compare
|
@cdecker tests seem to be a bit evened out now, if it's not too much trouble would you mind re-checking the liquid + alt-arch tests you ran? |
a00f221 to
75e5a8e
Compare
Ignored outputs don't end up in the same 'resolved' pathway as other tracked outputs do, so we mark them as moved when proposed/broadcast instead of when resolved (since they'll never flow through as resolved)
62e7599 to
0585717
Compare
For cheats, we do a little bit of weird accounting. First we 'update' our on-ledger balance to be the entirety of the channel's balance. Then, as outputs get resolved, we record the fees and outputs as withdrawals from this amount. It's possible that they might successfully 'cheat', in which case we record those as 'penalty' but debits (not credits).
We record htlcs when they're fulfilled as 'withdrawals' that are onchain. This should make use of the payment_hash that we stashed. Additionally, if an htlc spend comes through that's not ours, it's probably them resolving our attempted cheat; we should allow it to proceed without bombing, and just do our accounting as necessary. It'll all come out in the wash.
Fixes the tx type annotation in a few places.
For every withdrawal transaction emitted, we record each of the outputs plus the fees paid for this transaction.
If we don't save to disk, if the node restarts we'll lose them all and the resulting balance check at the end will be incorrect.
Mostly we update existing tests to account for channel balances. In a few places, new tests were needed as there wasn't an existing pathway that tested the chain-fees for a few penalty cases
Check that we account for push_msat and wallet withdrawal/deposits correctly
On node start we replay onchaind's transactions from the database/from our loaded htlc table. To keep things tidy, we shouldn't notify the ledger about these, so we wrap pretty much everything in a flag that tells us whether or not this is a replay. There's a very small corner case where dust transactions will get missed if the node crashes after the htlc has been added to the database but before we've successfully notified onchaind about it. Notably, most of the obtrusive updates to onchaind wrappings are due to the fact that we record dust (ignored outputs) before we receive confirmation of its confirmation.
Previously we were annotating every movement with the blockheight of lightningd at notification time. Which is lossy in terms of info, and won't be helpful for reorg reconciliation. Here we switch over to logging chain moves iff they've been confirmed. Next PR will fix this up for withdrawals, which are currently tagged with a blockheight of zero, since we log on successful send.
This moves the notification for our coin spends from when it's successfully submited to the mempool to when they're confirmed in a block. We also add an 'informational' notice tagged as `spend_track` which can be used to track which transaction a wallet output was spent in.
Changelog-Added: Plugins: new notification type, `coin_movement`, which tracks all fund movements for a node
Should make it easier to track when coin moves in the plugin are disjoint from what c-lightning says it's broadcast already.
It's possible for our peer to publish a commitment tx that has already updated our balance for an htlc before we've completed removing it from our commitment tx (aka before we've updated our balance). This used to crash, now we just update our balance (and the channel balance logs!) and keep going. If they've removed anything from our balance, we'll end up counting it as chain_fees below. Not ideal but fine... probably.
Wrap up more logic internally to the method call for htlcs. Also, don't touch part id if we're not the 'origin' Suggested-By: @rustyrussell
note that 'null' 'we_fulfilled's are going to be legacy from this release forward.
Canonicalize the signature for the 'tag-type' of coin moves by unique constructor/method calls. Suggested-By: @rustyrussell
Updates the unit of account to be the chain_id, which is the BIP173 name of the chain that the coins moved on. Suggested-By: @rustyrussell
These guys take a while to run, so let's just skip them on the valgrind/slow-machine combos :/
0585717 to
bc80300
Compare
|
Ack bc80300 |
This PR adds a new notification type,
coin_movementto c-ligthtning. By recording these notifications one may construct a canonical ledger for coin movements through a c-lightning node.Cribbed from the PLUGINS.md update that this PR entails:
coin_movementA notification for topic
coin_movementis sent to record themovement of coins. It is only triggered by finalized ledger updates,
i.e. only definitively resolved HTLCs or confirmed bitcoin transactions.
{ "coin_movement": { "version":1, "node_id":"03a7103a2322b811f7369cbb27fb213d30bbc0b012082fed3cad7e4498da2dc56b", "movement_idx":0, "type":"chain_mvt", "account_id":"wallet", "txid":"0159693d8f3876b4def468b208712c630309381e9d106a9836fa0a9571a28722", // (`chain_mvt` type only, mandatory) "utxo_txid":"0159693d8f3876b4def468b208712c630309381e9d106a9836fa0a9571a28722", // (`chain_mvt` type only, optional) "vout":1, // (`chain_mvt` type only, optional) "payment_hash": "xxx", // (either type, optional on `chain_mvt`) "part_id": 0, // (`channel_mvt` type only, mandatory) "credit":"2000000000msat", "debit":"0msat", "tag":"deposit", "blockheight":102, // (`channel_mvt` type only. may be null) "timestamp":1585948198, "unit_of_account":"btc" } }versionindicates which version of the coin movement data struct thisnotification adheres to.
node_idspecifies the node issuing the coin movement.movement_idxis an increment-only counter for coin moves emitted by this node.typemarks the underlying mechanism which moved these coins. There are two'types' of
coin_movements:channel_mvts, which occur as a result of htlcs being resolved and,chain_mvts, which occur as a result of bitcoin txs being mined.account_idis the name of this account. The node's wallet is named 'wallet',all channel funds' account are the channel id.
txidis the transaction id of the bitcoin transaction that triggered thisledger event.
utxo_txidandvoutidentify the bitcoin output which triggeredthis notification. (
chain_mvtonly) In most cases, theutxo_txidwill be thesame as the
txid, except forspend_tracknotficiations. Notifications taggedchain_feesandjournal_entrydo not have autxo_txidas they're notrepresented in the utxo set.
payment_hashis the hash of the preimage used to move this payment. Onlypresent for HTLC mediated moves (both
chain_mvtandchannel_mvt)A
chain_mvtwill have apayment_hashiff it's recording an htlc that wasfulfilled onchain.
part_idis an identifier for parts of a multi-part payment. useful foraggregating payments for an invoice or to indicate why a payment hash appears
multiple times.
channel_mvtonlycreditanddebitare millisatoshi denominated amounts of the fund movement. A'credit' is funds deposited into an account; a
debitis funds withdrawn.tagis a movement descriptor. Current tags are as follows:deposit: funds depositedwithdrawal: funds withdrawnchain_fees: funds paid for onchain fees.chain_mvtonlypenalty: funds paid or gained from a penalty tx.chain_mvtonlyinvoice: funds paid to or recieved from an invoice.channel_mvtonlyrouted: funds routed through this node.channel_mvtonlyjournal_entry: a balance reconciliation event, typically triggeredby a penalty tx onchain.
chain_mvtonlyonchain_htlc: funds moved via an htlc onchain.chain_mvtonlypushed: funds pushed to peer.channel_mvtonly.spend_track: informational notification about a wallet utxo spend.chain_mvtonly.blockheightis the block the txid is included in.chain_mvtonly. In thecase that an output is considered dust, c-lightning does not track its return to
our wallet. In those cases, the blockheight will be
null, as they're recordedbefore confirmation.
The
timestampis seconds since Unix epoch of the node's machine timeat the time lightningd broadcasts the notification.
unit_of_accountis the 'currency' this coin movememnt is denominated in.Resolves #3588