mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 23:24:27 +01:00
onchaind: use a point-of-last-resort if we see an unknown transaction.
This may have been supplied by the peer if it's nice and supports option_data_loss_protect. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
committed by
Christian Decker
parent
6aed936799
commit
1a4084442b
@@ -467,7 +467,8 @@ enum watch_result onchaind_funding_spent(struct channel *channel,
|
|||||||
channel->last_htlc_sigs,
|
channel->last_htlc_sigs,
|
||||||
tal_count(stubs),
|
tal_count(stubs),
|
||||||
channel->min_possible_feerate,
|
channel->min_possible_feerate,
|
||||||
channel->max_possible_feerate);
|
channel->max_possible_feerate,
|
||||||
|
channel->future_per_commitment_point);
|
||||||
subd_send_msg(channel->owner, take(msg));
|
subd_send_msg(channel->owner, take(msg));
|
||||||
|
|
||||||
/* FIXME: Don't queue all at once, use an empty cb... */
|
/* FIXME: Don't queue all at once, use an empty cb... */
|
||||||
|
|||||||
@@ -2117,6 +2117,94 @@ static void handle_their_unilateral(const struct bitcoin_tx *tx,
|
|||||||
wait_for_resolved(outs);
|
wait_for_resolved(outs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_unknown_commitment(const struct bitcoin_tx *tx,
|
||||||
|
u32 tx_blockheight,
|
||||||
|
u64 commit_num,
|
||||||
|
const struct bitcoin_txid *txid,
|
||||||
|
const struct pubkey *possible_remote_per_commitment_point,
|
||||||
|
const struct basepoints basepoints[NUM_SIDES],
|
||||||
|
const struct htlc_stub *htlcs,
|
||||||
|
const bool *tell_if_missing,
|
||||||
|
struct tracked_output **outs)
|
||||||
|
{
|
||||||
|
struct keyset *ks;
|
||||||
|
int to_us_output = -1;
|
||||||
|
u8 *local_script;
|
||||||
|
|
||||||
|
resolved_by_other(outs[0], txid, UNKNOWN_UNILATERAL);
|
||||||
|
|
||||||
|
if (!possible_remote_per_commitment_point)
|
||||||
|
goto search_done;
|
||||||
|
|
||||||
|
keyset = ks = tal(tx, struct keyset);
|
||||||
|
if (!derive_keyset(possible_remote_per_commitment_point,
|
||||||
|
&basepoints[REMOTE],
|
||||||
|
&basepoints[LOCAL],
|
||||||
|
ks))
|
||||||
|
status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
||||||
|
"Deriving keyset for possible_remote_per_commitment_point %s",
|
||||||
|
type_to_string(tmpctx, struct pubkey,
|
||||||
|
possible_remote_per_commitment_point));
|
||||||
|
|
||||||
|
local_script = scriptpubkey_p2wpkh(tmpctx, &keyset->other_payment_key);
|
||||||
|
for (size_t i = 0; i < tal_count(tx->output); i++) {
|
||||||
|
struct tracked_output *out;
|
||||||
|
|
||||||
|
if (local_script
|
||||||
|
&& scripteq(tx->output[i].script, local_script)) {
|
||||||
|
/* BOLT #5:
|
||||||
|
*
|
||||||
|
* - MAY take no action in regard to the associated
|
||||||
|
* `to_remote`, which is simply a P2WPKH output to
|
||||||
|
* the *local node*.
|
||||||
|
* - Note: `to_remote` is considered *resolved* by the
|
||||||
|
* commitment transaction itself.
|
||||||
|
*/
|
||||||
|
out = new_tracked_output(&outs, txid, tx_blockheight,
|
||||||
|
UNKNOWN_UNILATERAL,
|
||||||
|
i, tx->output[i].amount,
|
||||||
|
OUTPUT_TO_US, NULL, NULL, NULL);
|
||||||
|
ignore_output(out);
|
||||||
|
local_script = NULL;
|
||||||
|
|
||||||
|
/* Tell the master that it will want to add
|
||||||
|
* this UTXO to its outputs */
|
||||||
|
wire_sync_write(REQ_FD, towire_onchain_add_utxo(
|
||||||
|
tmpctx, txid, i,
|
||||||
|
possible_remote_per_commitment_point,
|
||||||
|
tx->output[i].amount,
|
||||||
|
tx_blockheight));
|
||||||
|
to_us_output = i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
search_done:
|
||||||
|
if (to_us_output == -1) {
|
||||||
|
status_broken("FUNDS LOST. Unknown commitment #%"PRIu64"!",
|
||||||
|
commit_num);
|
||||||
|
init_reply("ERROR: FUNDS LOST. Unknown commitment!");
|
||||||
|
} else {
|
||||||
|
status_broken("ERROR: Unknown commitment #%"PRIu64
|
||||||
|
", recovering our funds!",
|
||||||
|
commit_num);
|
||||||
|
init_reply("ERROR: Unknown commitment, recovering our funds!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tell master to give up on HTLCs immediately. */
|
||||||
|
for (size_t i = 0; i < tal_count(htlcs); i++) {
|
||||||
|
u8 *msg;
|
||||||
|
|
||||||
|
if (!tell_if_missing[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
msg = towire_onchain_missing_htlc_output(NULL, &htlcs[i]);
|
||||||
|
wire_sync_write(REQ_FD, take(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_for_resolved(outs);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
setup_locale();
|
setup_locale();
|
||||||
@@ -2136,6 +2224,7 @@ int main(int argc, char *argv[])
|
|||||||
struct htlc_stub *htlcs;
|
struct htlc_stub *htlcs;
|
||||||
bool *tell_if_missing, *tell_immediately;
|
bool *tell_if_missing, *tell_immediately;
|
||||||
u32 tx_blockheight;
|
u32 tx_blockheight;
|
||||||
|
struct pubkey *possible_remote_per_commitment_point;
|
||||||
|
|
||||||
subdaemon_setup(argc, argv);
|
subdaemon_setup(argc, argv);
|
||||||
|
|
||||||
@@ -2166,7 +2255,8 @@ int main(int argc, char *argv[])
|
|||||||
&remote_htlc_sigs,
|
&remote_htlc_sigs,
|
||||||
&num_htlcs,
|
&num_htlcs,
|
||||||
&min_possible_feerate,
|
&min_possible_feerate,
|
||||||
&max_possible_feerate)) {
|
&max_possible_feerate,
|
||||||
|
&possible_remote_per_commitment_point)) {
|
||||||
master_badmsg(WIRE_ONCHAIN_INIT, msg);
|
master_badmsg(WIRE_ONCHAIN_INIT, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2284,13 +2374,16 @@ int main(int argc, char *argv[])
|
|||||||
tell_if_missing,
|
tell_if_missing,
|
||||||
tell_immediately,
|
tell_immediately,
|
||||||
outs);
|
outs);
|
||||||
} else
|
} else {
|
||||||
status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
handle_unknown_commitment(tx, tx_blockheight,
|
||||||
"Unknown commitment index %"PRIu64
|
|
||||||
" for tx %s",
|
|
||||||
commit_num,
|
commit_num,
|
||||||
type_to_string(tmpctx, struct bitcoin_tx,
|
&txid,
|
||||||
tx));
|
possible_remote_per_commitment_point,
|
||||||
|
basepoints,
|
||||||
|
htlcs,
|
||||||
|
tell_if_missing,
|
||||||
|
outs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We're done! */
|
/* We're done! */
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ enum tx_type {
|
|||||||
/* Their unilateral: spends funding */
|
/* Their unilateral: spends funding */
|
||||||
THEIR_UNILATERAL,
|
THEIR_UNILATERAL,
|
||||||
|
|
||||||
|
/* Unknown unilateral (presumably theirs): spends funding */
|
||||||
|
UNKNOWN_UNILATERAL,
|
||||||
|
|
||||||
/* Our unilateral: spends funding */
|
/* Our unilateral: spends funding */
|
||||||
OUR_UNILATERAL,
|
OUR_UNILATERAL,
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ onchain_init,,htlc_signature,num_htlc_sigs*secp256k1_ecdsa_signature
|
|||||||
onchain_init,,num_htlcs,u64
|
onchain_init,,num_htlcs,u64
|
||||||
onchain_init,,min_possible_feerate,u32
|
onchain_init,,min_possible_feerate,u32
|
||||||
onchain_init,,max_possible_feerate,u32
|
onchain_init,,max_possible_feerate,u32
|
||||||
|
onchain_init,,possible_remote_per_commit_point,?struct pubkey
|
||||||
|
|
||||||
#include <onchaind/onchain_wire.h>
|
#include <onchaind/onchain_wire.h>
|
||||||
# This is all the HTLCs: one per message
|
# This is all the HTLCs: one per message
|
||||||
|
|||||||
|
@@ -37,7 +37,7 @@ bool fromwire_onchain_depth(const void *p UNNEEDED, struct bitcoin_txid *txid UN
|
|||||||
bool fromwire_onchain_htlc(const void *p UNNEEDED, struct htlc_stub *htlc UNNEEDED, bool *tell_if_missing UNNEEDED, bool *tell_immediately 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(); }
|
{ fprintf(stderr, "fromwire_onchain_htlc called!\n"); abort(); }
|
||||||
/* Generated stub for fromwire_onchain_init */
|
/* Generated stub for fromwire_onchain_init */
|
||||||
bool fromwire_onchain_init(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct shachain *shachain UNNEEDED, u64 *funding_amount_satoshi 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 *feerate_per_kw UNNEEDED, u64 *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 *funder 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)
|
bool fromwire_onchain_init(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct shachain *shachain UNNEEDED, u64 *funding_amount_satoshi 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 *feerate_per_kw UNNEEDED, u64 *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 *funder 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)
|
||||||
{ fprintf(stderr, "fromwire_onchain_init called!\n"); abort(); }
|
{ fprintf(stderr, "fromwire_onchain_init called!\n"); abort(); }
|
||||||
/* Generated stub for fromwire_onchain_known_preimage */
|
/* 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)
|
||||||
|
|||||||
@@ -1141,7 +1141,7 @@ def test_funder_feerate_reconnect(node_factory, bitcoind):
|
|||||||
|
|
||||||
|
|
||||||
@unittest.skipIf(not DEVELOPER, "needs LIGHTNINGD_DEV_LOG_IO")
|
@unittest.skipIf(not DEVELOPER, "needs LIGHTNINGD_DEV_LOG_IO")
|
||||||
def test_dataloss_protection(node_factory):
|
def test_dataloss_protection(node_factory, bitcoind):
|
||||||
l1 = node_factory.get_node(may_reconnect=True, log_all_io=True)
|
l1 = node_factory.get_node(may_reconnect=True, log_all_io=True)
|
||||||
l2 = node_factory.get_node(may_reconnect=True, log_all_io=True)
|
l2 = node_factory.get_node(may_reconnect=True, log_all_io=True)
|
||||||
|
|
||||||
@@ -1214,4 +1214,14 @@ def test_dataloss_protection(node_factory):
|
|||||||
l2.daemon.wait_for_log("Cannot broadcast our commitment tx: they have a future one")
|
l2.daemon.wait_for_log("Cannot broadcast our commitment tx: they have a future one")
|
||||||
assert not l2.daemon.is_in_log('sendrawtx exit 0')
|
assert not l2.daemon.is_in_log('sendrawtx exit 0')
|
||||||
|
|
||||||
# FIXME: l2 should still be able to collect onchain.
|
closetxid = only_one(bitcoind.rpc.getrawmempool(False))
|
||||||
|
|
||||||
|
# l2 should still recover something!
|
||||||
|
bitcoind.generate_block(1)
|
||||||
|
|
||||||
|
l2.daemon.wait_for_log("ERROR: Unknown commitment #2, recovering our funds!")
|
||||||
|
bitcoind.generate_block(100)
|
||||||
|
l2.daemon.wait_for_log('WIRE_ONCHAIN_ALL_IRREVOCABLY_RESOLVED')
|
||||||
|
|
||||||
|
# l2 should have it in wallet.
|
||||||
|
assert (closetxid, "confirmed") in set([(o['txid'], o['status']) for o in l2.rpc.listfunds()['outputs']])
|
||||||
|
|||||||
Reference in New Issue
Block a user