Browse Source

coin moves: don't log coin moves in onchaind if we're replaying

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.
nifty/pset-pre
lisa neigut 5 years ago
committed by Rusty Russell
parent
commit
9caf20f636
  1. 43
      lightningd/onchain_control.c
  2. 3
      lightningd/onchain_control.h
  3. 2
      lightningd/peer_control.c
  4. 2
      lightningd/peer_htlcs.c
  5. 3
      lightningd/test/run-invoice-select-inchan.c
  6. 4
      onchaind/onchain_wire.csv
  7. 170
      onchaind/onchaind.c
  8. 11
      onchaind/test/run-grind_feerate-bug.c
  9. 8
      onchaind/test/run-grind_feerate.c
  10. 3
      tests/test_closing.py
  11. 5
      wallet/test/run-wallet.c

43
lightningd/onchain_control.c

@ -52,7 +52,21 @@ static void onchaind_tell_fulfill(struct channel *channel)
if (!hin->preimage)
continue;
msg = towire_onchain_known_preimage(channel, hin->preimage);
/* Sooo these are *probably* replays since they're coming
* from the database but it's hard to be sure since we update
* the database before notifying onchaind about them.
* There's a *very* rare chance that we'll not log them,
* only in that we only make ledger records as a result of this call
* iff the output isn't deemed 'trackable'. So if we do miss a
* ledger record as a result of this decision, it's guaranteed to be
* impreceptibly tiny *and* not show up anywhere else in the node's
* utxo set.
*
* Aka a reconciliator's nightmare.
* The alternative is to double-count *every* ignored htlc output
* It's easier to delete than find a missing, but I'm banking on
* the rarity of failure here. (hahaha) */
msg = towire_onchain_known_preimage(channel, hin->preimage, false);
subd_send_msg(channel->owner, take(msg));
}
}
@ -68,10 +82,11 @@ static void handle_onchain_init_reply(struct channel *channel, const u8 *msg UNU
*/
static void onchain_tx_depth(struct channel *channel,
const struct bitcoin_txid *txid,
unsigned int depth)
unsigned int depth,
bool is_replay)
{
u8 *msg;
msg = towire_onchain_depth(channel, txid, depth);
msg = towire_onchain_depth(channel, txid, depth, is_replay);
subd_send_msg(channel->owner, take(msg));
}
@ -114,7 +129,7 @@ static enum watch_result onchain_tx_watched(struct lightningd *ld,
wallet_channeltxs_add(ld->wallet, channel,
WIRE_ONCHAIN_DEPTH, txid, 0, blockheight);
onchain_tx_depth(channel, txid, depth);
onchain_tx_depth(channel, txid, depth, false);
return KEEP_WATCHING;
}
@ -124,13 +139,13 @@ static void watch_tx_and_outputs(struct channel *channel,
/**
* Notify onchaind that an output was spent and register new watches.
*/
static void onchain_txo_spent(struct channel *channel, const struct bitcoin_tx *tx, size_t input_num, u32 blockheight)
static void onchain_txo_spent(struct channel *channel, const struct bitcoin_tx *tx, size_t input_num, u32 blockheight, bool is_replay)
{
u8 *msg;
watch_tx_and_outputs(channel, tx);
msg = towire_onchain_spent(channel, tx, input_num, blockheight);
msg = towire_onchain_spent(channel, tx, input_num, blockheight, is_replay);
subd_send_msg(channel->owner, take(msg));
}
@ -151,7 +166,7 @@ static enum watch_result onchain_txo_watched(struct channel *channel,
WIRE_ONCHAIN_SPENT, &txid, input_num,
block->height);
onchain_txo_spent(channel, tx, input_num, block->height);
onchain_txo_spent(channel, tx, input_num, block->height, false);
/* We don't need to keep watching: If this output is double-spent
* (reorg), we'll get a zero depth cb to onchain_tx_watched, and
@ -477,7 +492,8 @@ static void onchain_error(struct channel *channel,
* onchaind (like any other owner), and restart */
enum watch_result onchaind_funding_spent(struct channel *channel,
const struct bitcoin_tx *tx,
u32 blockheight)
u32 blockheight,
bool is_replay)
{
u8 *msg;
struct bitcoin_txid our_last_txid, txid;
@ -601,7 +617,8 @@ enum watch_result onchaind_funding_spent(struct channel *channel,
channel->min_possible_feerate,
channel->max_possible_feerate,
channel->future_per_commitment_point,
channel->option_static_remotekey);
channel->option_static_remotekey,
is_replay);
subd_send_msg(channel->owner, take(msg));
/* FIXME: Don't queue all at once, use an empty cb... */
@ -642,16 +659,18 @@ void onchaind_replay_channels(struct lightningd *ld)
for (size_t j = 0; j < tal_count(txs); j++) {
if (txs[j].type == WIRE_ONCHAIN_INIT) {
onchaind_funding_spent(chan, txs[j].tx,
txs[j].blockheight);
txs[j].blockheight,
true);
} else if (txs[j].type == WIRE_ONCHAIN_SPENT) {
onchain_txo_spent(chan, txs[j].tx,
txs[j].input_num,
txs[j].blockheight);
txs[j].blockheight,
true);
} else if (txs[j].type == WIRE_ONCHAIN_DEPTH) {
onchain_tx_depth(chan, &txs[j].txid,
txs[j].depth);
txs[j].depth, true);
} else {
fatal("unknown message of type %d during "

3
lightningd/onchain_control.h

@ -11,7 +11,8 @@ struct block;
enum watch_result onchaind_funding_spent(struct channel *channel,
const struct bitcoin_tx *tx,
u32 blockheight);
u32 blockheight,
bool is_replay);
void onchaind_replay_channels(struct lightningd *ld);

2
lightningd/peer_control.c

@ -1133,7 +1133,7 @@ static enum watch_result funding_spent(struct channel *channel,
wallet_channeltxs_add(channel->peer->ld->wallet, channel,
WIRE_ONCHAIN_INIT, &txid, 0, block->height);
return onchaind_funding_spent(channel, tx, block->height);
return onchaind_funding_spent(channel, tx, block->height, false);
}
void channel_watch_funding(struct lightningd *ld, struct channel *channel)

2
lightningd/peer_htlcs.c

@ -423,7 +423,7 @@ void fulfill_htlc(struct htlc_in *hin, const struct preimage *preimage)
}
if (channel_on_chain(channel)) {
msg = towire_onchain_known_preimage(hin, preimage);
msg = towire_onchain_known_preimage(hin, preimage, false);
} else {
struct fulfilled_htlc fulfilled_htlc;
fulfilled_htlc.id = hin->key.id;

3
lightningd/test/run-invoice-select-inchan.c

@ -257,7 +257,8 @@ void notify_invoice_payment(struct lightningd *ld UNNEEDED, struct amount_msat a
/* Generated stub for onchaind_funding_spent */
enum watch_result onchaind_funding_spent(struct channel *channel UNNEEDED,
const struct bitcoin_tx *tx UNNEEDED,
u32 blockheight UNNEEDED)
u32 blockheight UNNEEDED,
bool is_replay UNNEEDED)
{ fprintf(stderr, "onchaind_funding_spent called!\n"); abort(); }
/* Generated stub for param */
bool param(struct command *cmd UNNEEDED, const char *buffer UNNEEDED,

4
onchaind/onchain_wire.csv

@ -43,6 +43,7 @@ msgdata,onchain_init,min_possible_feerate,u32,
msgdata,onchain_init,max_possible_feerate,u32,
msgdata,onchain_init,possible_remote_per_commit_point,?pubkey,
msgdata,onchain_init,option_static_remotekey,bool,
msgdata,onchain_init,is_replay,bool,
#include <onchaind/onchain_wire.h>
# This is all the HTLCs: one per message
@ -65,11 +66,13 @@ msgtype,onchain_spent,5004
msgdata,onchain_spent,tx,bitcoin_tx,
msgdata,onchain_spent,input_num,u32,
msgdata,onchain_spent,blockheight,u32,
msgdata,onchain_spent,is_replay,bool,
# master->onchaind: We will receive more than one of these, as depth changes.
msgtype,onchain_depth,5005
msgdata,onchain_depth,txid,bitcoin_txid,
msgdata,onchain_depth,depth,u32,
msgdata,onchain_depth,is_replay,bool,
# onchaind->master: We don't want to watch this tx, or its outputs
msgtype,onchain_unwatch_tx,5006
@ -78,6 +81,7 @@ msgdata,onchain_unwatch_tx,txid,bitcoin_txid,
# master->onchaind: We know HTLC preimage
msgtype,onchain_known_preimage,5007
msgdata,onchain_known_preimage,preimage,preimage,
msgdata,onchain_known_preimage,is_replay,bool,
# onchaind->master: We discovered HTLC preimage
msgtype,onchain_extracted_preimage,5008

Can't render this file because it has a wrong number of fields in line 6.

170
onchaind/onchaind.c

@ -805,7 +805,7 @@ static enum wallet_tx_type onchain_txtype_to_wallet_txtype(enum tx_type t)
abort();
}
static void proposal_meets_depth(struct tracked_output *out)
static void proposal_meets_depth(struct tracked_output *out, bool is_replay)
{
/* If we simply wanted to ignore it after some depth */
if (!out->proposal->tx) {
@ -831,12 +831,15 @@ static void proposal_meets_depth(struct tracked_output *out)
struct amount_sat fees;
ignore_output(out);
if (!is_replay) {
/* log the coin movements here, since we're not
* going to wait til we hear about it */
bitcoin_txid(out->proposal->tx, &txid);
fees = record_chain_fees_tx(&txid, out->proposal->tx);
record_channel_withdrawal_minus_fees(&txid, out, fees);
}
}
/* Otherwise we will get a callback when it's in a block. */
}
@ -844,7 +847,8 @@ static void proposal_meets_depth(struct tracked_output *out)
static void propose_resolution(struct tracked_output *out,
const struct bitcoin_tx *tx,
unsigned int depth_required,
enum tx_type tx_type)
enum tx_type tx_type,
bool is_replay)
{
status_debug("Propose handling %s/%s by %s (%s) after %u blocks",
tx_type_name(out->tx_type),
@ -859,13 +863,14 @@ static void propose_resolution(struct tracked_output *out,
out->proposal->tx_type = tx_type;
if (depth_required == 0)
proposal_meets_depth(out);
proposal_meets_depth(out, is_replay);
}
static void propose_resolution_at_block(struct tracked_output *out,
const struct bitcoin_tx *tx,
unsigned int block_required,
enum tx_type tx_type)
enum tx_type tx_type,
bool is_replay)
{
u32 depth;
@ -874,7 +879,7 @@ static void propose_resolution_at_block(struct tracked_output *out,
depth = 0;
else /* Note that out->tx_blockheight is already at depth 1 */
depth = block_required - out->tx_blockheight + 1;
propose_resolution(out, tx, depth, tx_type);
propose_resolution(out, tx, depth, tx_type, is_replay);
}
static bool is_valid_sig(const u8 *e)
@ -1251,7 +1256,8 @@ static void resolve_htlc_tx(const struct chainparams *chainparams,
size_t out_index,
const struct bitcoin_tx *htlc_tx,
const struct bitcoin_txid *htlc_txid,
u32 tx_blockheight)
u32 tx_blockheight,
bool is_replay)
{
struct tracked_output *out;
struct bitcoin_tx *tx;
@ -1295,7 +1301,8 @@ static void resolve_htlc_tx(const struct chainparams *chainparams,
tx = tx_to_us(*outs, delayed_payment_to_us, out, to_self_delay[LOCAL],
0, NULL, 0, wscript, &tx_type, htlc_feerate);
propose_resolution(out, tx, to_self_delay[LOCAL], tx_type);
propose_resolution(out, tx, to_self_delay[LOCAL], tx_type,
is_replay);
}
/* BOLT #5:
@ -1311,7 +1318,8 @@ static void steal_htlc_tx(const struct chainparams *chainparams,
const struct bitcoin_tx *htlc_tx,
struct bitcoin_txid *htlc_txid,
u32 htlc_tx_blockheight,
enum tx_type htlc_tx_type)
enum tx_type htlc_tx_type,
bool is_replay)
{
struct bitcoin_tx *tx;
enum tx_type tx_type = OUR_PENALTY_TX;
@ -1362,10 +1370,12 @@ static void steal_htlc_tx(const struct chainparams *chainparams,
status_debug("recording chain fees for peer's htlc tx, that we're about to steal"
" the output of. fees: %s",
type_to_string(tmpctx, struct amount_sat, &fees));
if (!is_replay)
update_ledger_chain_fees(htlc_txid, fees);
/* annnd done! */
propose_resolution(htlc_out, tx, 0, tx_type);
propose_resolution(htlc_out, tx, 0, tx_type, is_replay);
}
static void onchain_annotate_txout(const struct bitcoin_txid *txid, u32 outnum,
@ -1387,7 +1397,8 @@ static void output_spent(const struct chainparams *chainparams,
struct tracked_output ***outs,
const struct bitcoin_tx *tx,
u32 input_num,
u32 tx_blockheight)
u32 tx_blockheight,
bool is_replay)
{
struct bitcoin_txid txid, tmptxid, spendertxid;
@ -1412,8 +1423,9 @@ static void output_spent(const struct chainparams *chainparams,
if (out->resolved->tx_type == OUR_HTLC_SUCCESS_TX
|| out->resolved->tx_type == OUR_HTLC_TIMEOUT_TX)
resolve_htlc_tx(chainparams, outs, i, tx, &txid,
tx_blockheight);
tx_blockheight, is_replay);
if (!is_replay)
record_coin_movements(out, out->proposal->tx, &txid);
return;
}
@ -1422,6 +1434,7 @@ static void output_spent(const struct chainparams *chainparams,
case OUTPUT_TO_US:
case DELAYED_OUTPUT_TO_US:
unknown_spend(out, tx);
if (!is_replay)
record_coin_loss(&txid, out);
break;
@ -1429,7 +1442,8 @@ static void output_spent(const struct chainparams *chainparams,
if (out->tx_type == THEIR_REVOKED_UNILATERAL) {
/* we've actually got a 'new' output here */
steal_htlc_tx(chainparams, out, outs, tx, &txid,
tx_blockheight, THEIR_HTLC_TIMEOUT_TO_THEM);
tx_blockheight, THEIR_HTLC_TIMEOUT_TO_THEM,
is_replay);
} else {
/* We ignore this timeout tx, since we should
* resolve by ignoring once we reach depth. */
@ -1457,7 +1471,8 @@ static void output_spent(const struct chainparams *chainparams,
handle_htlc_onchain_fulfill(out, tx);
if (out->tx_type == THEIR_REVOKED_UNILATERAL) {
steal_htlc_tx(chainparams, out, outs, tx, &txid,
tx_blockheight, OUR_HTLC_FULFILL_TO_THEM);
tx_blockheight, OUR_HTLC_FULFILL_TO_THEM,
is_replay);
} else {
/* BOLT #5:
*
@ -1470,6 +1485,7 @@ static void output_spent(const struct chainparams *chainparams,
*/
ignore_output(out);
if (!is_replay)
record_htlc_fulfilled(&txid, out, false);
onchain_annotate_txout(
&spendertxid, out->outnum,
@ -1486,6 +1502,7 @@ static void output_spent(const struct chainparams *chainparams,
case DELAYED_CHEAT_OUTPUT_TO_THEM:
/* They successfully spent a delayed revoked output */
resolved_by_other(out, &txid, THEIR_DELAYED_CHEAT);
if (!is_replay)
record_their_successful_cheat(&txid, out);
break;
/* Um, we don't track these! */
@ -1547,7 +1564,8 @@ static void update_resolution_depth(struct tracked_output *out, u32 depth)
}
static void tx_new_depth(struct tracked_output **outs,
const struct bitcoin_txid *txid, u32 depth)
const struct bitcoin_txid *txid, u32 depth,
bool is_replay)
{
size_t i;
@ -1581,7 +1599,7 @@ static void tx_new_depth(struct tracked_output **outs,
if (outs[i]->proposal
&& bitcoin_txid_eq(&outs[i]->txid, txid)
&& depth >= outs[i]->proposal->depth_required) {
proposal_meets_depth(outs[i]);
proposal_meets_depth(outs[i], is_replay);
}
}
}
@ -1613,7 +1631,8 @@ static void tx_new_depth(struct tracked_output **outs,
/* Master makes sure we only get told preimages once other node is committed. */
static void handle_preimage(const struct chainparams *chainparams,
struct tracked_output **outs,
const struct preimage *preimage)
const struct preimage *preimage,
bool is_replay)
{
size_t i;
struct sha256 sha;
@ -1684,7 +1703,8 @@ static void handle_preimage(const struct chainparams *chainparams,
tx, &sig, outs[i]->remote_htlc_sig, preimage,
outs[i]->wscript);
bitcoin_tx_input_set_witness(tx, 0, take(witness));
propose_resolution(outs[i], tx, 0, OUR_HTLC_SUCCESS_TX);
propose_resolution(outs[i], tx, 0, OUR_HTLC_SUCCESS_TX,
is_replay);
} else {
enum tx_type tx_type = THEIR_HTLC_FULFILL_TO_US;
@ -1705,8 +1725,9 @@ static void handle_preimage(const struct chainparams *chainparams,
0, preimage, sizeof(*preimage),
outs[i]->wscript, &tx_type,
htlc_feerate);
propose_resolution(outs[i], tx, 0, tx_type);
if (tx_type == IGNORING_TINY_PAYMENT) {
propose_resolution(outs[i], tx, 0, tx_type,
is_replay);
if (!is_replay && tx_type == IGNORING_TINY_PAYMENT) {
struct bitcoin_txid txid;
bitcoin_txid(tx, &txid);
record_htlc_fulfilled(&txid, outs[i], true);
@ -1785,18 +1806,19 @@ static void wait_for_resolved(const struct chainparams *chainparams,
struct bitcoin_tx *tx;
u32 input_num, depth, tx_blockheight;
struct preimage preimage;
bool is_replay;
status_debug("Got new message %s",
onchain_wire_type_name(fromwire_peektype(msg)));
if (fromwire_onchain_depth(msg, &txid, &depth))
tx_new_depth(outs, &txid, depth);
if (fromwire_onchain_depth(msg, &txid, &depth, &is_replay))
tx_new_depth(outs, &txid, depth, is_replay);
else if (fromwire_onchain_spent(msg, msg, &tx, &input_num,
&tx_blockheight)) {
&tx_blockheight, &is_replay)) {
tx->chainparams = chainparams;
output_spent(chainparams, &outs, tx, input_num, tx_blockheight);
} else if (fromwire_onchain_known_preimage(msg, &preimage))
handle_preimage(chainparams, outs, &preimage);
output_spent(chainparams, &outs, tx, input_num, tx_blockheight, is_replay);
} else if (fromwire_onchain_known_preimage(msg, &preimage, &is_replay))
handle_preimage(chainparams, outs, &preimage, is_replay);
else if (!handle_dev_memleak(outs, msg))
master_badmsg(-1, msg);
@ -1820,7 +1842,8 @@ static void handle_mutual_close(const struct chainparams *chainparams,
const struct bitcoin_txid *txid,
struct tracked_output **outs,
const struct bitcoin_tx *tx,
int our_outnum)
int our_outnum,
bool is_replay)
{
struct amount_sat our_out;
init_reply("Tracking mutual close transaction");
@ -1838,6 +1861,7 @@ static void handle_mutual_close(const struct chainparams *chainparams,
*/
resolved_by_other(outs[0], txid, MUTUAL_CLOSE);
if (!is_replay) {
/* It's possible there's no to_us output */
if (our_outnum > -1) {
struct amount_asset asset;
@ -1848,6 +1872,7 @@ static void handle_mutual_close(const struct chainparams *chainparams,
our_out = AMOUNT_SAT(0);
record_mutual_closure(txid, our_out, our_outnum);
}
wait_for_resolved(chainparams, outs);
}
@ -1883,7 +1908,8 @@ static size_t resolve_our_htlc_ourcommit(const struct chainparams *chainparams,
struct tracked_output *out,
const size_t *matches,
const struct htlc_stub *htlcs,
u8 **htlc_scripts)
u8 **htlc_scripts,
bool is_replay)
{
struct bitcoin_tx *tx = NULL;
struct bitcoin_signature localsig;
@ -1962,7 +1988,7 @@ static size_t resolve_our_htlc_ourcommit(const struct chainparams *chainparams,
/* Steals tx onto out */
propose_resolution_at_block(out, tx, htlcs[matches[i]].cltv_expiry,
OUR_HTLC_TIMEOUT_TX);
OUR_HTLC_TIMEOUT_TX, is_replay);
return matches[i];
}
@ -1984,7 +2010,8 @@ static u32 matches_cltv(const size_t *matches,
static size_t resolve_our_htlc_theircommit(struct tracked_output *out,
const size_t *matches,
const struct htlc_stub *htlcs,
u8 **htlc_scripts)
u8 **htlc_scripts,
bool is_replay)
{
struct bitcoin_tx *tx;
enum tx_type tx_type = OUR_HTLC_TIMEOUT_TO_US;
@ -2003,7 +2030,7 @@ static size_t resolve_our_htlc_theircommit(struct tracked_output *out,
tx = tx_to_us(out, remote_htlc_to_us, out, 0, cltv_expiry, NULL, 0,
htlc_scripts[matches[0]], &tx_type, htlc_feerate);
propose_resolution_at_block(out, tx, cltv_expiry, tx_type);
propose_resolution_at_block(out, tx, cltv_expiry, tx_type, is_replay);
/* They're all equivalent: might as well use first one. */
return matches[0];
@ -2013,7 +2040,8 @@ static size_t resolve_our_htlc_theircommit(struct tracked_output *out,
static size_t resolve_their_htlc(struct tracked_output *out,
const size_t *matches,
const struct htlc_stub *htlcs,
u8 **htlc_scripts)
u8 **htlc_scripts,
bool is_replay)
{
size_t which_htlc;
@ -2050,7 +2078,7 @@ static size_t resolve_their_htlc(struct tracked_output *out,
/* If we hit timeout depth, resolve by ignoring. */
propose_resolution_at_block(out, NULL, htlcs[which_htlc].cltv_expiry,
THEIR_HTLC_TIMEOUT_TO_THEM);
THEIR_HTLC_TIMEOUT_TO_THEM, is_replay);
return which_htlc;
}
@ -2125,7 +2153,8 @@ static void handle_our_unilateral(const struct bitcoin_tx *tx,
const bool *tell_if_missing,
const bool *tell_immediately,
const secp256k1_ecdsa_signature *remote_htlc_sigs,
struct tracked_output **outs)
struct tracked_output **outs,
bool is_replay)
{
u8 **htlc_scripts;
u8 *local_wscript, *script[NUM_SIDES];
@ -2272,7 +2301,7 @@ static void handle_our_unilateral(const struct bitcoin_tx *tx,
* output is *resolved* by the spending transaction
*/
propose_resolution(out, to_us, to_self_delay[LOCAL],
tx_type);
tx_type, is_replay);
script[LOCAL] = NULL;
add_amt(&our_outs, amt);
@ -2327,7 +2356,8 @@ static void handle_our_unilateral(const struct bitcoin_tx *tx,
which_htlc = resolve_our_htlc_ourcommit(tx->chainparams,
out, matches,
htlcs,
htlc_scripts);
htlc_scripts,
is_replay);
add_amt(&our_outs, amt);
} else {
out = new_tracked_output(tx->chainparams,
@ -2346,7 +2376,8 @@ static void handle_our_unilateral(const struct bitcoin_tx *tx,
*/
/* Tells us which htlc to use */
which_htlc = resolve_their_htlc(out, matches, htlcs,
htlc_scripts);
htlc_scripts,
is_replay);
add_amt(&their_outs, amt);
}
out->htlc = htlcs[which_htlc];
@ -2361,16 +2392,17 @@ static void handle_our_unilateral(const struct bitcoin_tx *tx,
note_missing_htlcs(htlc_scripts, htlcs,
tell_if_missing, tell_immediately);
if (!is_replay)
record_chain_fees_unilateral(txid, outs[0]->sat,
their_outs, our_outs);
wait_for_resolved(tx->chainparams, outs);
}
/* We produce individual penalty txs. It's less efficient, but avoids them
* using HTLC txs to block our penalties for long enough to pass the CSV
* delay */
static void steal_to_them_output(struct tracked_output *out)
static void steal_to_them_output(struct tracked_output *out, bool is_replay)
{
u8 *wscript;
struct bitcoin_tx *tx;
@ -2390,10 +2422,10 @@ static void steal_to_them_output(struct tracked_output *out)
tx = tx_to_us(tmpctx, penalty_to_us, out, 0xFFFFFFFF, 0, &ONE,
sizeof(ONE), wscript, &tx_type, penalty_feerate);
propose_resolution(out, tx, 0, tx_type);
propose_resolution(out, tx, 0, tx_type, is_replay);
}
static void steal_htlc(struct tracked_output *out)
static void steal_htlc(struct tracked_output *out, bool is_replay)
{
struct bitcoin_tx *tx;
enum tx_type tx_type = OUR_PENALTY_TX;
@ -2410,7 +2442,7 @@ static void steal_htlc(struct tracked_output *out)
tx = tx_to_us(out, penalty_to_us, out, 0xFFFFFFFF, 0, der, sizeof(der),
out->wscript, &tx_type, penalty_feerate);
propose_resolution(out, tx, 0, tx_type);
propose_resolution(out, tx, 0, tx_type, is_replay);
}
/* Tell wallet that we have discovered a UTXO from a to-remote output,
@ -2491,7 +2523,8 @@ static void handle_their_cheat(const struct bitcoin_tx *tx,
const struct htlc_stub *htlcs,
const bool *tell_if_missing,
const bool *tell_immediately,
struct tracked_output **outs)
struct tracked_output **outs,
bool is_replay)
{
u8 **htlc_scripts;
u8 *remote_wscript, *script[NUM_SIDES];
@ -2506,6 +2539,7 @@ static void handle_their_cheat(const struct bitcoin_tx *tx,
init_reply("Tracking their illegal close: taking all funds");
onchain_annotate_txin(
txid, 0, TX_CHANNEL_UNILATERAL | TX_CHANNEL_CHEAT | TX_THEIRS);
if (!is_replay)
update_ledger_cheat(txid, outs[0]);
/* BOLT #5:
@ -2652,6 +2686,8 @@ static void handle_their_cheat(const struct bitcoin_tx *tx,
i, amt,
OUTPUT_TO_US, NULL, NULL, NULL);
ignore_output(out);
if (!is_replay)
record_channel_withdrawal(txid, out);
tell_wallet_to_remote(tx, i, txid,
@ -2676,7 +2712,7 @@ static void handle_their_cheat(const struct bitcoin_tx *tx,
amt,
DELAYED_CHEAT_OUTPUT_TO_THEM,
NULL, NULL, NULL);
steal_to_them_output(out);
steal_to_them_output(out, is_replay);
script[REMOTE] = NULL;
add_amt(&total_outs, amt);
continue;
@ -2708,7 +2744,7 @@ static void handle_their_cheat(const struct bitcoin_tx *tx,
&htlcs[which_htlc],
htlc_scripts[which_htlc],
NULL);
steal_htlc(out);
steal_htlc(out, is_replay);
add_amt(&total_outs, amt);
} else {
out = new_tracked_output(tx->chainparams,
@ -2727,7 +2763,7 @@ static void handle_their_cheat(const struct bitcoin_tx *tx,
* * spend the *commitment tx* using the payment preimage (if known).
* * spend the *HTLC-timeout tx*, if the remote node has published it.
*/
steal_htlc(out);
steal_htlc(out, is_replay);
add_amt(&total_outs, amt);
}
htlc_scripts[which_htlc] = NULL;
@ -2741,6 +2777,8 @@ static void handle_their_cheat(const struct bitcoin_tx *tx,
assert(amt_ok);
status_debug("recording chain fees for their cheat %s",
type_to_string(tmpctx, struct amount_sat, &fee_cost));
if (!is_replay)
update_ledger_chain_fees(txid, fee_cost);
wait_for_resolved(tx->chainparams, outs);
@ -2754,7 +2792,8 @@ static void handle_their_unilateral(const struct bitcoin_tx *tx,
const struct htlc_stub *htlcs,
const bool *tell_if_missing,
const bool *tell_immediately,
struct tracked_output **outs)
struct tracked_output **outs,
bool is_replay)
{
u8 **htlc_scripts;
u8 *remote_wscript, *script[NUM_SIDES];
@ -2900,6 +2939,8 @@ static void handle_their_unilateral(const struct bitcoin_tx *tx,
i, amt,
OUTPUT_TO_US, NULL, NULL, NULL);
ignore_output(out);
if (!is_replay)
record_channel_withdrawal(txid, out);
tell_wallet_to_remote(tx, i, txid,
@ -2956,7 +2997,8 @@ static void handle_their_unilateral(const struct bitcoin_tx *tx,
which_htlc = resolve_our_htlc_theircommit(out,
matches,
htlcs,
htlc_scripts);
htlc_scripts,
is_replay);
add_amt(&our_outs, amt);
} else {
out = new_tracked_output(tx->chainparams,
@ -2974,7 +3016,7 @@ static void handle_their_unilateral(const struct bitcoin_tx *tx,
* Commitment, Remote Offers]
*/
which_htlc = resolve_their_htlc(out, matches, htlcs,
htlc_scripts);
htlc_scripts, is_replay);
add_amt(&their_outs, amt);
}
out->htlc = htlcs[which_htlc];
@ -2984,8 +3026,11 @@ static void handle_their_unilateral(const struct bitcoin_tx *tx,
note_missing_htlcs(htlc_scripts, htlcs,
tell_if_missing, tell_immediately);
if (!is_replay)
record_chain_fees_unilateral(txid, outs[0]->sat,
their_outs, our_outs);
wait_for_resolved(tx->chainparams, outs);
}
@ -3037,7 +3082,8 @@ static void handle_unknown_commitment(const struct bitcoin_tx *tx,
const struct basepoints basepoints[NUM_SIDES],
const struct htlc_stub *htlcs,
const bool *tell_if_missing,
struct tracked_output **outs)
struct tracked_output **outs,
bool is_replay)
{
int to_us_output = -1;
u8 *local_script;
@ -3106,8 +3152,12 @@ static void handle_unknown_commitment(const struct bitcoin_tx *tx,
i, amt,
OUTPUT_TO_US, NULL, NULL, NULL);
ignore_output(out);
if (!is_replay)
record_channel_withdrawal(txid, out);
add_amt(&amt_salvaged, amt);
tell_wallet_to_remote(tx, i, txid,
tx_blockheight,
local_script,
@ -3132,6 +3182,7 @@ search_done:
/* update our accounting notions for this channel.
* should result in a channel balance of zero */
if (!is_replay)
update_ledger_unknown(txid, amt_salvaged);
/* Tell master to give up on HTLCs immediately. */
@ -3170,6 +3221,7 @@ int main(int argc, char *argv[])
u32 tx_blockheight;
struct pubkey *possible_remote_per_commitment_point;
int mutual_outnum;
bool open_is_replay;
subdaemon_setup(argc, argv);
@ -3206,7 +3258,8 @@ int main(int argc, char *argv[])
&min_possible_feerate,
&max_possible_feerate,
&possible_remote_per_commitment_point,
&option_static_remotekey)) {
&option_static_remotekey,
&open_is_replay)) {
master_badmsg(WIRE_ONCHAIN_INIT, msg);
}
@ -3262,7 +3315,7 @@ int main(int argc, char *argv[])
* [BOLT #2: Channel Close](02-peer-protocol.md#channel-close)).
*/
if (is_mutual_close(tx, scriptpubkey[LOCAL], scriptpubkey[REMOTE], &mutual_outnum))
handle_mutual_close(tx->chainparams, &txid, outs, tx, mutual_outnum);
handle_mutual_close(tx->chainparams, &txid, outs, tx, mutual_outnum, open_is_replay);
else {
/* BOLT #5:
*
@ -3286,7 +3339,8 @@ int main(int argc, char *argv[])
htlcs,
tell_if_missing, tell_immediately,
remote_htlc_sigs,
outs);
outs,
open_is_replay);
/* BOLT #5:
*
* 3. The ugly way (*revoked transaction close*): one of the
@ -3302,7 +3356,8 @@ int main(int argc, char *argv[])
basepoints,
htlcs,
tell_if_missing, tell_immediately,
outs);
outs,
open_is_replay);
/* BOLT #5:
*
* There may be more than one valid, *unrevoked* commitment
@ -3321,7 +3376,8 @@ int main(int argc, char *argv[])
htlcs,
tell_if_missing,
tell_immediately,
outs);
outs,
open_is_replay);
} else if (commit_num == revocations_received(&shachain) + 1) {
status_debug("Their unilateral tx, new commit point");
handle_their_unilateral(tx, tx_blockheight,
@ -3331,7 +3387,8 @@ int main(int argc, char *argv[])
htlcs,
tell_if_missing,
tell_immediately,
outs);
outs,
open_is_replay);
} else {
handle_unknown_commitment(tx, tx_blockheight,
commit_num,
@ -3340,7 +3397,8 @@ int main(int argc, char *argv[])
basepoints,
htlcs,
tell_if_missing,
outs);
outs,
open_is_replay);
}
}

11
onchaind/test/run-grind_feerate-bug.c

@ -34,7 +34,7 @@ const void *fromwire_fail(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
bool fromwire_hsm_get_per_commitment_point_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct pubkey *per_commitment_point UNNEEDED, struct secret **old_commitment_secret UNNEEDED)
{ fprintf(stderr, "fromwire_hsm_get_per_commitment_point_reply called!\n"); abort(); }
/* Generated stub for fromwire_onchain_depth */
bool fromwire_onchain_depth(const void *p UNNEEDED, struct bitcoin_txid *txid UNNEEDED, u32 *depth UNNEEDED)
bool fromwire_onchain_depth(const void *p UNNEEDED, struct bitcoin_txid *txid UNNEEDED, u32 *depth UNNEEDED, bool *is_replay UNNEEDED)
{ fprintf(stderr, "fromwire_onchain_depth called!\n"); abort(); }
/* Generated stub for fromwire_onchain_dev_memleak */
bool fromwire_onchain_dev_memleak(const void *p UNNEEDED)
@ -43,13 +43,13 @@ bool fromwire_onchain_dev_memleak(const void *p UNNEEDED)
bool fromwire_onchain_htlc(const void *p UNNEEDED, struct htlc_stub *htlc UNNEEDED, bool *tell_if_missing UNNEEDED, bool *tell_immediately UNNEEDED)
{ fprintf(stderr, "fromwire_onchain_htlc called!\n"); abort(); }
/* Generated stub for fromwire_onchain_init */
bool fromwire_onchain_init(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct shachain *shachain UNNEEDED, const struct chainparams **chainparams UNNEEDED, struct amount_sat *funding_amount_satoshi UNNEEDED, struct amount_msat *our_msat UNNEEDED, struct pubkey *old_remote_per_commitment_point UNNEEDED, struct pubkey *remote_per_commitment_point UNNEEDED, u32 *local_to_self_delay UNNEEDED, u32 *remote_to_self_delay UNNEEDED, u32 *delayed_to_us_feerate UNNEEDED, u32 *htlc_feerate UNNEEDED, u32 *penalty_feerate UNNEEDED, struct amount_sat *local_dust_limit_satoshi UNNEEDED, struct bitcoin_txid *our_broadcast_txid UNNEEDED, u8 **local_scriptpubkey UNNEEDED, u8 **remote_scriptpubkey UNNEEDED, struct pubkey *ourwallet_pubkey UNNEEDED, enum side *opener UNNEEDED, struct basepoints *local_basepoints UNNEEDED, struct basepoints *remote_basepoints UNNEEDED, struct bitcoin_tx **tx UNNEEDED, u32 *tx_blockheight UNNEEDED, u32 *reasonable_depth UNNEEDED, secp256k1_ecdsa_signature **htlc_signature UNNEEDED, u64 *num_htlcs UNNEEDED, u32 *min_possible_feerate UNNEEDED, u32 *max_possible_feerate UNNEEDED, struct pubkey **possible_remote_per_commit_point UNNEEDED, bool *option_static_remotekey UNNEEDED)
bool fromwire_onchain_init(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct shachain *shachain UNNEEDED, const struct chainparams **chainparams UNNEEDED, struct amount_sat *funding_amount_satoshi UNNEEDED, struct amount_msat *our_msat UNNEEDED, struct pubkey *old_remote_per_commitment_point UNNEEDED, struct pubkey *remote_per_commitment_point UNNEEDED, u32 *local_to_self_delay UNNEEDED, u32 *remote_to_self_delay UNNEEDED, u32 *delayed_to_us_feerate UNNEEDED, u32 *htlc_feerate UNNEEDED, u32 *penalty_feerate UNNEEDED, struct amount_sat *local_dust_limit_satoshi UNNEEDED, struct bitcoin_txid *our_broadcast_txid UNNEEDED, u8 **local_scriptpubkey UNNEEDED, u8 **remote_scriptpubkey UNNEEDED, struct pubkey *ourwallet_pubkey UNNEEDED, enum side *opener UNNEEDED, struct basepoints *local_basepoints UNNEEDED, struct basepoints *remote_basepoints UNNEEDED, struct bitcoin_tx **tx UNNEEDED, u32 *tx_blockheight UNNEEDED, u32 *reasonable_depth UNNEEDED, secp256k1_ecdsa_signature **htlc_signature UNNEEDED, u64 *num_htlcs UNNEEDED, u32 *min_possible_feerate UNNEEDED, u32 *max_possible_feerate UNNEEDED, struct pubkey **possible_remote_per_commit_point UNNEEDED, bool *option_static_remotekey UNNEEDED, bool *is_replay UNNEEDED)
{ fprintf(stderr, "fromwire_onchain_init called!\n"); abort(); }
/* Generated stub for fromwire_onchain_known_preimage */
bool fromwire_onchain_known_preimage(const void *p UNNEEDED, struct preimage *preimage UNNEEDED)
bool fromwire_onchain_known_preimage(const void *p UNNEEDED, struct preimage *preimage UNNEEDED, bool *is_replay UNNEEDED)
{ fprintf(stderr, "fromwire_onchain_known_preimage called!\n"); abort(); }
/* Generated stub for fromwire_onchain_spent */
bool fromwire_onchain_spent(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct bitcoin_tx **tx UNNEEDED, u32 *input_num UNNEEDED, u32 *blockheight UNNEEDED)
bool fromwire_onchain_spent(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct bitcoin_tx **tx UNNEEDED, u32 *input_num UNNEEDED, u32 *blockheight UNNEEDED, bool *is_replay UNNEEDED)
{ fprintf(stderr, "fromwire_onchain_spent called!\n"); abort(); }
/* Generated stub for fromwire_peektype */
int fromwire_peektype(const u8 *cursor UNNEEDED)
@ -329,7 +329,8 @@ int main(void)
out,
matches,
htlcs,
htlc_scripts);
htlc_scripts,
false);
assert(ret == 2);
take_cleanup();
tal_free(tmpctx);

8
onchaind/test/run-grind_feerate.c

@ -38,7 +38,7 @@ bool fromwire_hsm_get_per_commitment_point_reply(const tal_t *ctx UNNEEDED, cons
bool fromwire_hsm_sign_tx_reply(const void *p UNNEEDED, struct bitcoin_signature *sig UNNEEDED)
{ fprintf(stderr, "fromwire_hsm_sign_tx_reply called!\n"); abort(); }
/* Generated stub for fromwire_onchain_depth */
bool fromwire_onchain_depth(const void *p UNNEEDED, struct bitcoin_txid *txid UNNEEDED, u32 *depth UNNEEDED)
bool fromwire_onchain_depth(const void *p UNNEEDED, struct bitcoin_txid *txid UNNEEDED, u32 *depth UNNEEDED, bool *is_replay UNNEEDED)
{ fprintf(stderr, "fromwire_onchain_depth called!\n"); abort(); }
/* Generated stub for fromwire_onchain_dev_memleak */
bool fromwire_onchain_dev_memleak(const void *p UNNEEDED)
@ -47,13 +47,13 @@ bool fromwire_onchain_dev_memleak(const void *p UNNEEDED)
bool fromwire_onchain_htlc(const void *p UNNEEDED, struct htlc_stub *htlc UNNEEDED, bool *tell_if_missing UNNEEDED, bool *tell_immediately UNNEEDED)
{ fprintf(stderr, "fromwire_onchain_htlc called!\n"); abort(); }
/* Generated stub for fromwire_onchain_init */
bool fromwire_onchain_init(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct shachain *shachain UNNEEDED, const struct chainparams **chainparams UNNEEDED, struct amount_sat *funding_amount_satoshi UNNEEDED, struct amount_msat *our_msat UNNEEDED, struct pubkey *old_remote_per_commitment_point UNNEEDED, struct pubkey *remote_per_commitment_point UNNEEDED, u32 *local_to_self_delay UNNEEDED, u32 *remote_to_self_delay UNNEEDED, u32 *delayed_to_us_feerate UNNEEDED, u32 *htlc_feerate UNNEEDED, u32 *penalty_feerate UNNEEDED, struct amount_sat *local_dust_limit_satoshi UNNEEDED, struct bitcoin_txid *our_broadcast_txid UNNEEDED, u8 **local_scriptpubkey UNNEEDED, u8 **remote_scriptpubkey UNNEEDED, struct pubkey *ourwallet_pubkey UNNEEDED, enum side *opener UNNEEDED, struct basepoints *local_basepoints UNNEEDED, struct basepoints *remote_basepoints UNNEEDED, struct bitcoin_tx **tx UNNEEDED, u32 *tx_blockheight UNNEEDED, u32 *reasonable_depth UNNEEDED, secp256k1_ecdsa_signature **htlc_signature UNNEEDED, u64 *num_htlcs UNNEEDED, u32 *min_possible_feerate UNNEEDED, u32 *max_possible_feerate UNNEEDED, struct pubkey **possible_remote_per_commit_point UNNEEDED, bool *option_static_remotekey UNNEEDED)
bool fromwire_onchain_init(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct shachain *shachain UNNEEDED, const struct chainparams **chainparams UNNEEDED, struct amount_sat *funding_amount_satoshi UNNEEDED, struct amount_msat *our_msat UNNEEDED, struct pubkey *old_remote_per_commitment_point UNNEEDED, struct pubkey *remote_per_commitment_point UNNEEDED, u32 *local_to_self_delay UNNEEDED, u32 *remote_to_self_delay UNNEEDED, u32 *delayed_to_us_feerate UNNEEDED, u32 *htlc_feerate UNNEEDED, u32 *penalty_feerate UNNEEDED, struct amount_sat *local_dust_limit_satoshi UNNEEDED, struct bitcoin_txid *our_broadcast_txid UNNEEDED, u8 **local_scriptpubkey UNNEEDED, u8 **remote_scriptpubkey UNNEEDED, struct pubkey *ourwallet_pubkey UNNEEDED, enum side *opener UNNEEDED, struct basepoints *local_basepoints UNNEEDED, struct basepoints *remote_basepoints UNNEEDED, struct bitcoin_tx **tx UNNEEDED, u32 *tx_blockheight UNNEEDED, u32 *reasonable_depth UNNEEDED, secp256k1_ecdsa_signature **htlc_signature UNNEEDED, u64 *num_htlcs UNNEEDED, u32 *min_possible_feerate UNNEEDED, u32 *max_possible_feerate UNNEEDED, struct pubkey **possible_remote_per_commit_point UNNEEDED, bool *option_static_remotekey UNNEEDED, bool *is_replay UNNEEDED)
{ fprintf(stderr, "fromwire_onchain_init called!\n"); abort(); }
/* Generated stub for fromwire_onchain_known_preimage */
bool fromwire_onchain_known_preimage(const void *p UNNEEDED, struct preimage *preimage UNNEEDED)
bool fromwire_onchain_known_preimage(const void *p UNNEEDED, struct preimage *preimage UNNEEDED, bool *is_replay UNNEEDED)
{ fprintf(stderr, "fromwire_onchain_known_preimage called!\n"); abort(); }
/* Generated stub for fromwire_onchain_spent */
bool fromwire_onchain_spent(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct bitcoin_tx **tx UNNEEDED, u32 *input_num UNNEEDED, u32 *blockheight UNNEEDED)
bool fromwire_onchain_spent(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct bitcoin_tx **tx UNNEEDED, u32 *input_num UNNEEDED, u32 *blockheight UNNEEDED, bool *is_replay UNNEEDED)
{ fprintf(stderr, "fromwire_onchain_spent called!\n"); abort(); }
/* Generated stub for fromwire_tal_arrn */
u8 *fromwire_tal_arrn(const tal_t *ctx UNNEEDED,

3
tests/test_closing.py

@ -1222,8 +1222,7 @@ def test_onchain_dust_out(node_factory, bitcoind, executor):
# Payment failed, BTW
assert only_one(l2.rpc.listinvoices('onchain_dust_out')['invoices'])['status'] == 'unpaid'
# l1 repeats the onchaind outputs, so we get duplicated emissions. FIXME??
assert account_balance(l1, channel_id) == -1000000000
assert account_balance(l1, channel_id) == 0
assert account_balance(l2, channel_id) == 0

5
wallet/test/run-wallet.c

@ -434,7 +434,8 @@ void notify_forward_event(struct lightningd *ld UNNEEDED,
/* Generated stub for onchaind_funding_spent */
enum watch_result onchaind_funding_spent(struct channel *channel UNNEEDED,
const struct bitcoin_tx *tx UNNEEDED,
u32 blockheight UNNEEDED)
u32 blockheight UNNEEDED,
bool is_replay UNNEEDED)
{ fprintf(stderr, "onchaind_funding_spent called!\n"); abort(); }
/* Generated stub for onion_decode */
struct onion_payload *onion_decode(const tal_t *ctx UNNEEDED,
@ -703,7 +704,7 @@ u8 *towire_invalid_realm(const tal_t *ctx UNNEEDED)
u8 *towire_onchain_dev_memleak(const tal_t *ctx UNNEEDED)
{ fprintf(stderr, "towire_onchain_dev_memleak called!\n"); abort(); }
/* Generated stub for towire_onchain_known_preimage */
u8 *towire_onchain_known_preimage(const tal_t *ctx UNNEEDED, const struct preimage *preimage UNNEEDED)
u8 *towire_onchain_known_preimage(const tal_t *ctx UNNEEDED, const struct preimage *preimage UNNEEDED, bool is_replay UNNEEDED)
{ fprintf(stderr, "towire_onchain_known_preimage called!\n"); abort(); }
/* Generated stub for towire_permanent_channel_failure */
u8 *towire_permanent_channel_failure(const tal_t *ctx UNNEEDED)

Loading…
Cancel
Save