mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-26 20:30:59 +01:00
coin moves: record onchain movements after they've been resolved
We pass them back to lightningd who sends out a notification for them
This commit is contained in:
parent
175515b914
commit
e8d10edbe5
6 changed files with 189 additions and 0 deletions
|
@ -178,6 +178,24 @@ static void watch_tx_and_outputs(struct channel *channel,
|
||||||
onchain_txo_watched);
|
onchain_txo_watched);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_onchain_log_coin_move(struct channel *channel, const u8 *msg)
|
||||||
|
{
|
||||||
|
struct channel_id channel_id;
|
||||||
|
struct chain_coin_mvt *mvt = tal(NULL, struct chain_coin_mvt);
|
||||||
|
|
||||||
|
if (!fromwire_onchain_notify_coin_mvt(msg, mvt)) {
|
||||||
|
channel_internal_error(channel, "Invalid onchain notify_coin_mvt");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
derive_channel_id(&channel_id, &channel->funding_txid,
|
||||||
|
channel->funding_outnum);
|
||||||
|
mvt->account_name =
|
||||||
|
type_to_string(mvt, struct channel_id, &channel_id);
|
||||||
|
notify_chain_mvt(channel->peer->ld, mvt);
|
||||||
|
tal_free(mvt);
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_onchain_broadcast_tx(struct channel *channel, const u8 *msg)
|
static void handle_onchain_broadcast_tx(struct channel *channel, const u8 *msg)
|
||||||
{
|
{
|
||||||
struct bitcoin_tx *tx;
|
struct bitcoin_tx *tx;
|
||||||
|
@ -384,6 +402,10 @@ static unsigned int onchain_msg(struct subd *sd, const u8 *msg, const int *fds U
|
||||||
onchain_annotate_txout(sd->channel, msg);
|
onchain_annotate_txout(sd->channel, msg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case WIRE_ONCHAIN_NOTIFY_COIN_MVT:
|
||||||
|
handle_onchain_log_coin_move(sd->channel, msg);
|
||||||
|
break;
|
||||||
|
|
||||||
/* We send these, not receive them */
|
/* We send these, not receive them */
|
||||||
case WIRE_ONCHAIN_INIT:
|
case WIRE_ONCHAIN_INIT:
|
||||||
case WIRE_ONCHAIN_SPENT:
|
case WIRE_ONCHAIN_SPENT:
|
||||||
|
|
|
@ -50,6 +50,7 @@ ONCHAIND_COMMON_OBJS := \
|
||||||
common/amount.o \
|
common/amount.o \
|
||||||
common/bigsize.o \
|
common/bigsize.o \
|
||||||
common/bip32.o \
|
common/bip32.o \
|
||||||
|
common/coin_mvt.o \
|
||||||
common/daemon.o \
|
common/daemon.o \
|
||||||
common/daemon_conn.o \
|
common/daemon_conn.o \
|
||||||
common/derive_basepoints.o \
|
common/derive_basepoints.o \
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <common/coin_mvt.h>
|
||||||
#include <common/derive_basepoints.h>
|
#include <common/derive_basepoints.h>
|
||||||
#include <common/htlc_wire.h>
|
#include <common/htlc_wire.h>
|
||||||
#include <common/wallet.h>
|
#include <common/wallet.h>
|
||||||
|
@ -120,3 +121,5 @@ msgdata,onchain_annotate_txin,txid,bitcoin_txid,
|
||||||
msgdata,onchain_annotate_txin,innum,u32,
|
msgdata,onchain_annotate_txin,innum,u32,
|
||||||
msgdata,onchain_annotate_txin,type,enum wallet_tx_type,
|
msgdata,onchain_annotate_txin,type,enum wallet_tx_type,
|
||||||
|
|
||||||
|
msgtype,onchain_notify_coin_mvt,5037
|
||||||
|
msgdata,onchain_notify_coin_mvt,mvt,chain_coin_mvt,
|
||||||
|
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <ccan/mem/mem.h>
|
#include <ccan/mem/mem.h>
|
||||||
#include <ccan/tal/str/str.h>
|
#include <ccan/tal/str/str.h>
|
||||||
#include <common/amount.h>
|
#include <common/amount.h>
|
||||||
|
#include <common/coin_mvt.h>
|
||||||
#include <common/derive_basepoints.h>
|
#include <common/derive_basepoints.h>
|
||||||
#include <common/htlc_tx.h>
|
#include <common/htlc_tx.h>
|
||||||
#include <common/initial_commit_tx.h>
|
#include <common/initial_commit_tx.h>
|
||||||
|
@ -122,6 +123,136 @@ struct tracked_output {
|
||||||
struct sha256 *payment_hash;
|
struct sha256 *payment_hash;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void send_coin_mvt(struct chain_coin_mvt *mvt TAKES)
|
||||||
|
{
|
||||||
|
wire_sync_write(REQ_FD,
|
||||||
|
take(towire_onchain_notify_coin_mvt(NULL, mvt)));
|
||||||
|
|
||||||
|
if (taken(mvt))
|
||||||
|
tal_free(mvt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void record_htlc_fulfilled(const struct bitcoin_txid *txid,
|
||||||
|
struct tracked_output *out,
|
||||||
|
bool we_fulfilled)
|
||||||
|
{
|
||||||
|
struct chain_coin_mvt *mvt;
|
||||||
|
|
||||||
|
/* we're recording the *deposit* of a utxo which contained channel
|
||||||
|
* funds (htlc).
|
||||||
|
*
|
||||||
|
* since we really don't know if this was a 'routed' or 'destination'
|
||||||
|
* htlc here, we record it as a 'deposit/withdrawal' type */
|
||||||
|
mvt = new_chain_coin_mvt_sat(NULL, NULL,
|
||||||
|
txid, &out->txid,
|
||||||
|
out->outnum,
|
||||||
|
out->payment_hash,
|
||||||
|
ONCHAIN_HTLC,
|
||||||
|
out->sat, we_fulfilled,
|
||||||
|
BTC);
|
||||||
|
|
||||||
|
send_coin_mvt(take(mvt));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_ledger_chain_fees(const struct bitcoin_txid *txid,
|
||||||
|
struct amount_sat fees)
|
||||||
|
{
|
||||||
|
struct chain_coin_mvt *mvt;
|
||||||
|
mvt = new_chain_coin_mvt_sat(NULL, NULL,
|
||||||
|
txid, NULL, 0, NULL,
|
||||||
|
CHAIN_FEES, fees,
|
||||||
|
false, BTC);
|
||||||
|
|
||||||
|
if (!mvt)
|
||||||
|
status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
||||||
|
"unable to convert %s to msat",
|
||||||
|
type_to_string(tmpctx, struct amount_sat,
|
||||||
|
&fees));
|
||||||
|
send_coin_mvt(take(mvt));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Log the fees paid on this transaction as 'chain fees'. note that
|
||||||
|
* you *cannot* pass a chaintopology-originated tx to this method,
|
||||||
|
* as they don't have the input_amounts populated */
|
||||||
|
static struct amount_sat record_chain_fees_tx(const struct bitcoin_txid *txid,
|
||||||
|
const struct bitcoin_tx *tx)
|
||||||
|
{
|
||||||
|
struct amount_sat fees;
|
||||||
|
fees = bitcoin_tx_compute_fee(tx);
|
||||||
|
status_debug("recording chain fees for tx %s",
|
||||||
|
type_to_string(tmpctx, struct bitcoin_txid, txid));
|
||||||
|
update_ledger_chain_fees(txid, fees);
|
||||||
|
return fees;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void record_channel_withdrawal_minus_fees(const struct bitcoin_txid *tx_txid,
|
||||||
|
struct tracked_output *out,
|
||||||
|
struct amount_sat fees)
|
||||||
|
{
|
||||||
|
struct chain_coin_mvt *mvt;
|
||||||
|
struct amount_sat emitted_amt;
|
||||||
|
|
||||||
|
if (!amount_sat_sub(&emitted_amt, out->sat, fees))
|
||||||
|
status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
||||||
|
"unable to subtract %s from %s",
|
||||||
|
type_to_string(tmpctx, struct amount_sat,
|
||||||
|
&fees),
|
||||||
|
type_to_string(tmpctx, struct amount_sat,
|
||||||
|
&out->sat));
|
||||||
|
|
||||||
|
mvt = new_chain_coin_mvt_sat(NULL, NULL,
|
||||||
|
tx_txid, &out->txid,
|
||||||
|
out->outnum, NULL, WITHDRAWAL,
|
||||||
|
emitted_amt, false,
|
||||||
|
BTC);
|
||||||
|
|
||||||
|
if (!mvt)
|
||||||
|
status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
||||||
|
"unable to convert %s to msat",
|
||||||
|
type_to_string(tmpctx, struct amount_sat,
|
||||||
|
&out->sat));
|
||||||
|
|
||||||
|
send_coin_mvt(take(mvt));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool is_our_htlc_tx(struct tracked_output *out)
|
||||||
|
{
|
||||||
|
return out->resolved &&
|
||||||
|
(out->resolved->tx_type == OUR_HTLC_TIMEOUT_TX
|
||||||
|
|| out->resolved->tx_type == OUR_HTLC_SUCCESS_TX);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_channel_deposit(struct tracked_output *out)
|
||||||
|
{
|
||||||
|
return out->resolved &&
|
||||||
|
(out->resolved->tx_type == THEIR_HTLC_FULFILL_TO_US
|
||||||
|
|| out->resolved->tx_type == OUR_HTLC_SUCCESS_TX);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void record_coin_movements(struct tracked_output *out,
|
||||||
|
const struct bitcoin_tx *tx,
|
||||||
|
const struct bitcoin_txid *txid)
|
||||||
|
{
|
||||||
|
struct amount_sat fees;
|
||||||
|
/* there is a case where we've fulfilled an htlc onchain,
|
||||||
|
* in which case we log a deposit to the channel */
|
||||||
|
if (is_channel_deposit(out))
|
||||||
|
record_htlc_fulfilled(txid, out, true);
|
||||||
|
|
||||||
|
|
||||||
|
/* record fees paid for the tx here */
|
||||||
|
/* FIXME: for now, every resolution generates its own tx,
|
||||||
|
* this will need to be updated if we switch to batching */
|
||||||
|
fees = record_chain_fees_tx(txid, tx);
|
||||||
|
|
||||||
|
/* we don't record a channel withdrawal until we get to
|
||||||
|
* the 'exit' utxo, which for local commitment htlc txs
|
||||||
|
* is the child htlc_tx's output */
|
||||||
|
if (!is_our_htlc_tx(out))
|
||||||
|
record_channel_withdrawal_minus_fees(txid, out, fees);
|
||||||
|
}
|
||||||
|
|
||||||
/* We vary feerate until signature they offered matches. */
|
/* We vary feerate until signature they offered matches. */
|
||||||
static bool grind_htlc_tx_fee(struct amount_sat *fee,
|
static bool grind_htlc_tx_fee(struct amount_sat *fee,
|
||||||
struct bitcoin_tx *tx,
|
struct bitcoin_tx *tx,
|
||||||
|
@ -1064,6 +1195,8 @@ static void output_spent(const struct chainparams *chainparams,
|
||||||
|| out->resolved->tx_type == OUR_HTLC_TIMEOUT_TX)
|
|| out->resolved->tx_type == OUR_HTLC_TIMEOUT_TX)
|
||||||
resolve_htlc_tx(chainparams, outs, i, tx, &txid,
|
resolve_htlc_tx(chainparams, outs, i, tx, &txid,
|
||||||
tx_blockheight);
|
tx_blockheight);
|
||||||
|
|
||||||
|
record_coin_movements(out, out->proposal->tx, &txid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,18 @@ void memleak_remove_referenced(struct htable *memtable UNNEEDED, const void *roo
|
||||||
void memleak_scan_region(struct htable *memtable UNNEEDED,
|
void memleak_scan_region(struct htable *memtable UNNEEDED,
|
||||||
const void *p UNNEEDED, size_t bytelen UNNEEDED)
|
const void *p UNNEEDED, size_t bytelen UNNEEDED)
|
||||||
{ fprintf(stderr, "memleak_scan_region called!\n"); abort(); }
|
{ fprintf(stderr, "memleak_scan_region called!\n"); abort(); }
|
||||||
|
/* Generated stub for new_chain_coin_mvt_sat */
|
||||||
|
struct chain_coin_mvt *new_chain_coin_mvt_sat(const tal_t *ctx UNNEEDED,
|
||||||
|
const char *account_name UNNEEDED,
|
||||||
|
const struct bitcoin_txid *tx_txid UNNEEDED,
|
||||||
|
const struct bitcoin_txid *output_txid UNNEEDED,
|
||||||
|
u32 vout UNNEEDED,
|
||||||
|
struct sha256 *payment_hash UNNEEDED,
|
||||||
|
enum mvt_tag tag UNNEEDED,
|
||||||
|
struct amount_sat amt_sat UNNEEDED,
|
||||||
|
bool is_credit UNNEEDED,
|
||||||
|
enum mvt_unit_type unit UNNEEDED)
|
||||||
|
{ fprintf(stderr, "new_chain_coin_mvt_sat called!\n"); abort(); }
|
||||||
/* Generated stub for notleak_ */
|
/* Generated stub for notleak_ */
|
||||||
void *notleak_(const void *ptr UNNEEDED, bool plus_children UNNEEDED)
|
void *notleak_(const void *ptr UNNEEDED, bool plus_children UNNEEDED)
|
||||||
{ fprintf(stderr, "notleak_ called!\n"); abort(); }
|
{ fprintf(stderr, "notleak_ called!\n"); abort(); }
|
||||||
|
@ -168,6 +180,9 @@ u8 *towire_onchain_init_reply(const tal_t *ctx UNNEEDED)
|
||||||
/* Generated stub for towire_onchain_missing_htlc_output */
|
/* Generated stub for towire_onchain_missing_htlc_output */
|
||||||
u8 *towire_onchain_missing_htlc_output(const tal_t *ctx UNNEEDED, const struct htlc_stub *htlc UNNEEDED)
|
u8 *towire_onchain_missing_htlc_output(const tal_t *ctx UNNEEDED, const struct htlc_stub *htlc UNNEEDED)
|
||||||
{ fprintf(stderr, "towire_onchain_missing_htlc_output called!\n"); abort(); }
|
{ fprintf(stderr, "towire_onchain_missing_htlc_output called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire_onchain_notify_coin_mvt */
|
||||||
|
u8 *towire_onchain_notify_coin_mvt(const tal_t *ctx UNNEEDED, const struct chain_coin_mvt *mvt UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire_onchain_notify_coin_mvt called!\n"); abort(); }
|
||||||
/* Generated stub for towire_onchain_unwatch_tx */
|
/* Generated stub for towire_onchain_unwatch_tx */
|
||||||
u8 *towire_onchain_unwatch_tx(const tal_t *ctx UNNEEDED, const struct bitcoin_txid *txid UNNEEDED)
|
u8 *towire_onchain_unwatch_tx(const tal_t *ctx UNNEEDED, const struct bitcoin_txid *txid UNNEEDED)
|
||||||
{ fprintf(stderr, "towire_onchain_unwatch_tx called!\n"); abort(); }
|
{ fprintf(stderr, "towire_onchain_unwatch_tx called!\n"); abort(); }
|
||||||
|
|
|
@ -109,6 +109,18 @@ void memleak_remove_referenced(struct htable *memtable UNNEEDED, const void *roo
|
||||||
void memleak_scan_region(struct htable *memtable UNNEEDED,
|
void memleak_scan_region(struct htable *memtable UNNEEDED,
|
||||||
const void *p UNNEEDED, size_t bytelen UNNEEDED)
|
const void *p UNNEEDED, size_t bytelen UNNEEDED)
|
||||||
{ fprintf(stderr, "memleak_scan_region called!\n"); abort(); }
|
{ fprintf(stderr, "memleak_scan_region called!\n"); abort(); }
|
||||||
|
/* Generated stub for new_chain_coin_mvt_sat */
|
||||||
|
struct chain_coin_mvt *new_chain_coin_mvt_sat(const tal_t *ctx UNNEEDED,
|
||||||
|
const char *account_name UNNEEDED,
|
||||||
|
const struct bitcoin_txid *tx_txid UNNEEDED,
|
||||||
|
const struct bitcoin_txid *output_txid UNNEEDED,
|
||||||
|
u32 vout UNNEEDED,
|
||||||
|
struct sha256 *payment_hash UNNEEDED,
|
||||||
|
enum mvt_tag tag UNNEEDED,
|
||||||
|
struct amount_sat amt_sat UNNEEDED,
|
||||||
|
bool is_credit UNNEEDED,
|
||||||
|
enum mvt_unit_type unit UNNEEDED)
|
||||||
|
{ fprintf(stderr, "new_chain_coin_mvt_sat called!\n"); abort(); }
|
||||||
/* Generated stub for notleak_ */
|
/* Generated stub for notleak_ */
|
||||||
void *notleak_(const void *ptr UNNEEDED, bool plus_children UNNEEDED)
|
void *notleak_(const void *ptr UNNEEDED, bool plus_children UNNEEDED)
|
||||||
{ fprintf(stderr, "notleak_ called!\n"); abort(); }
|
{ fprintf(stderr, "notleak_ called!\n"); abort(); }
|
||||||
|
@ -186,6 +198,9 @@ u8 *towire_onchain_init_reply(const tal_t *ctx UNNEEDED)
|
||||||
/* Generated stub for towire_onchain_missing_htlc_output */
|
/* Generated stub for towire_onchain_missing_htlc_output */
|
||||||
u8 *towire_onchain_missing_htlc_output(const tal_t *ctx UNNEEDED, const struct htlc_stub *htlc UNNEEDED)
|
u8 *towire_onchain_missing_htlc_output(const tal_t *ctx UNNEEDED, const struct htlc_stub *htlc UNNEEDED)
|
||||||
{ fprintf(stderr, "towire_onchain_missing_htlc_output called!\n"); abort(); }
|
{ fprintf(stderr, "towire_onchain_missing_htlc_output called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire_onchain_notify_coin_mvt */
|
||||||
|
u8 *towire_onchain_notify_coin_mvt(const tal_t *ctx UNNEEDED, const struct chain_coin_mvt *mvt UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire_onchain_notify_coin_mvt called!\n"); abort(); }
|
||||||
/* Generated stub for towire_onchain_unwatch_tx */
|
/* Generated stub for towire_onchain_unwatch_tx */
|
||||||
u8 *towire_onchain_unwatch_tx(const tal_t *ctx UNNEEDED, const struct bitcoin_txid *txid UNNEEDED)
|
u8 *towire_onchain_unwatch_tx(const tal_t *ctx UNNEEDED, const struct bitcoin_txid *txid UNNEEDED)
|
||||||
{ fprintf(stderr, "towire_onchain_unwatch_tx called!\n"); abort(); }
|
{ fprintf(stderr, "towire_onchain_unwatch_tx called!\n"); abort(); }
|
||||||
|
|
Loading…
Add table
Reference in a new issue