mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 15:14:23 +01:00
onchaind: add recovery scans for option-will-fund
option_will_fund changes the to_remote/to_local commitment tx outputs by altering the CSV lock for leased channels. We need to grind/scan for these outputs now, provided the defaults don't work.
This commit is contained in:
@@ -36,6 +36,7 @@
|
|||||||
/* stdin == requests */
|
/* stdin == requests */
|
||||||
#define REQ_FD STDIN_FILENO
|
#define REQ_FD STDIN_FILENO
|
||||||
#define HSM_FD 3
|
#define HSM_FD 3
|
||||||
|
#define max(a, b) ((a) > (b) ? (a) : (b))
|
||||||
|
|
||||||
/* Required in various places: keys for commitment transaction. */
|
/* Required in various places: keys for commitment transaction. */
|
||||||
static const struct keyset *keyset;
|
static const struct keyset *keyset;
|
||||||
@@ -2583,12 +2584,66 @@ static u8 *scriptpubkey_to_remote(const tal_t *ctx,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void our_unilateral_to_us(struct tracked_output ***outs,
|
||||||
|
const struct tx_parts *tx,
|
||||||
|
u32 tx_blockheight,
|
||||||
|
size_t index,
|
||||||
|
struct amount_sat amt,
|
||||||
|
u16 sequence,
|
||||||
|
const u8 *local_scriptpubkey,
|
||||||
|
const u8 *local_wscript,
|
||||||
|
bool is_replay)
|
||||||
|
{
|
||||||
|
struct bitcoin_tx *to_us;
|
||||||
|
struct tracked_output *out;
|
||||||
|
enum tx_type tx_type = OUR_DELAYED_RETURN_TO_WALLET;
|
||||||
|
|
||||||
|
/* BOLT #5:
|
||||||
|
*
|
||||||
|
* A node:
|
||||||
|
* - upon discovering its *local commitment
|
||||||
|
* transaction*:
|
||||||
|
* - SHOULD spend the `to_local` output to a
|
||||||
|
* convenient address.
|
||||||
|
* - MUST wait until the `OP_CHECKSEQUENCEVERIFY`
|
||||||
|
* delay has passed (as specified by the remote
|
||||||
|
* node's `to_self_delay` field) before spending
|
||||||
|
* the output.
|
||||||
|
*/
|
||||||
|
out = new_tracked_output(outs, &tx->txid, tx_blockheight,
|
||||||
|
OUR_UNILATERAL, index,
|
||||||
|
amt,
|
||||||
|
DELAYED_OUTPUT_TO_US,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
/* BOLT #3:
|
||||||
|
*
|
||||||
|
* The output is spent by an input with
|
||||||
|
* `nSequence` field set to `to_self_delay` (which can
|
||||||
|
* only be valid after that duration has passed) and
|
||||||
|
* witness:
|
||||||
|
*
|
||||||
|
* <local_delayedsig> <>
|
||||||
|
*/
|
||||||
|
to_us = tx_to_us(out, delayed_payment_to_us, out,
|
||||||
|
sequence, 0, NULL, 0,
|
||||||
|
local_wscript, &tx_type,
|
||||||
|
delayed_to_us_feerate);
|
||||||
|
|
||||||
|
/* BOLT #5:
|
||||||
|
*
|
||||||
|
* Note: if the output is spent (as recommended), the
|
||||||
|
* output is *resolved* by the spending transaction
|
||||||
|
*/
|
||||||
|
propose_resolution(out, to_us, sequence, tx_type, is_replay);
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_our_unilateral(const struct tx_parts *tx,
|
static void handle_our_unilateral(const struct tx_parts *tx,
|
||||||
u32 tx_blockheight,
|
u32 tx_blockheight,
|
||||||
const struct basepoints basepoints[NUM_SIDES],
|
const struct basepoints basepoints[NUM_SIDES],
|
||||||
const struct htlc_stub *htlcs,
|
const struct htlc_stub *htlcs,
|
||||||
const bool *tell_if_missing,
|
const bool *tell_if_missing,
|
||||||
const bool *tell_immediately,
|
const bool *tell_immediately,
|
||||||
|
const enum side opener,
|
||||||
const struct bitcoin_signature *remote_htlc_sigs,
|
const struct bitcoin_signature *remote_htlc_sigs,
|
||||||
struct tracked_output **outs,
|
struct tracked_output **outs,
|
||||||
bool is_replay)
|
bool is_replay)
|
||||||
@@ -2701,47 +2756,10 @@ static void handle_our_unilateral(const struct tx_parts *tx,
|
|||||||
} else if (script[LOCAL]
|
} else if (script[LOCAL]
|
||||||
&& wally_tx_output_scripteq(tx->outputs[i],
|
&& wally_tx_output_scripteq(tx->outputs[i],
|
||||||
script[LOCAL])) {
|
script[LOCAL])) {
|
||||||
struct bitcoin_tx *to_us;
|
our_unilateral_to_us(&outs, tx, tx_blockheight,
|
||||||
enum tx_type tx_type = OUR_DELAYED_RETURN_TO_WALLET;
|
i, amt, to_self_delay[LOCAL],
|
||||||
|
script[LOCAL],
|
||||||
/* BOLT #5:
|
local_wscript, is_replay);
|
||||||
*
|
|
||||||
* A node:
|
|
||||||
* - upon discovering its *local commitment
|
|
||||||
* transaction*:
|
|
||||||
* - SHOULD spend the `to_local` output to a
|
|
||||||
* convenient address.
|
|
||||||
* - MUST wait until the `OP_CHECKSEQUENCEVERIFY`
|
|
||||||
* delay has passed (as specified by the remote
|
|
||||||
* node's `to_self_delay` field) before spending
|
|
||||||
* the output.
|
|
||||||
*/
|
|
||||||
out = new_tracked_output(&outs, &tx->txid, tx_blockheight,
|
|
||||||
OUR_UNILATERAL, i,
|
|
||||||
amt,
|
|
||||||
DELAYED_OUTPUT_TO_US,
|
|
||||||
NULL, NULL, NULL);
|
|
||||||
/* BOLT #3:
|
|
||||||
*
|
|
||||||
* The output is spent by an input with
|
|
||||||
* `nSequence` field set to `to_self_delay` (which can
|
|
||||||
* only be valid after that duration has passed) and
|
|
||||||
* witness:
|
|
||||||
*
|
|
||||||
* <local_delayedsig> <>
|
|
||||||
*/
|
|
||||||
to_us = tx_to_us(out, delayed_payment_to_us, out,
|
|
||||||
to_self_delay[LOCAL], 0, NULL, 0,
|
|
||||||
local_wscript, &tx_type,
|
|
||||||
delayed_to_us_feerate);
|
|
||||||
|
|
||||||
/* BOLT #5:
|
|
||||||
*
|
|
||||||
* Note: if the output is spent (as recommended), the
|
|
||||||
* output is *resolved* by the spending transaction
|
|
||||||
*/
|
|
||||||
propose_resolution(out, to_us, to_self_delay[LOCAL],
|
|
||||||
tx_type, is_replay);
|
|
||||||
|
|
||||||
script[LOCAL] = NULL;
|
script[LOCAL] = NULL;
|
||||||
add_amt(&our_outs, amt);
|
add_amt(&our_outs, amt);
|
||||||
@@ -2798,6 +2816,81 @@ static void handle_our_unilateral(const struct tx_parts *tx,
|
|||||||
matches = match_htlc_output(tmpctx, tx->outputs[i], htlc_scripts);
|
matches = match_htlc_output(tmpctx, tx->outputs[i], htlc_scripts);
|
||||||
/* FIXME: limp along when this happens! */
|
/* FIXME: limp along when this happens! */
|
||||||
if (tal_count(matches) == 0) {
|
if (tal_count(matches) == 0) {
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
/* Maybe they're using option_will_fund? */
|
||||||
|
if (opener == REMOTE && script[LOCAL]) {
|
||||||
|
status_debug("Grinding for our to_local");
|
||||||
|
/* We already tried `1` */
|
||||||
|
for (size_t csv = 2;
|
||||||
|
csv <= LEASE_RATE_DURATION;
|
||||||
|
csv++) {
|
||||||
|
|
||||||
|
local_wscript
|
||||||
|
= to_self_wscript(tmpctx,
|
||||||
|
to_self_delay[LOCAL],
|
||||||
|
csv, keyset);
|
||||||
|
|
||||||
|
script[LOCAL]
|
||||||
|
= scriptpubkey_p2wsh(tmpctx,
|
||||||
|
local_wscript);
|
||||||
|
if (!wally_tx_output_scripteq(
|
||||||
|
tx->outputs[i],
|
||||||
|
script[LOCAL]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
our_unilateral_to_us(&outs, tx,
|
||||||
|
tx_blockheight,
|
||||||
|
i, amt,
|
||||||
|
max(to_self_delay[LOCAL], csv),
|
||||||
|
script[LOCAL],
|
||||||
|
local_wscript,
|
||||||
|
is_replay);
|
||||||
|
|
||||||
|
script[LOCAL] = NULL;
|
||||||
|
add_amt(&our_outs, amt);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (opener == LOCAL && script[REMOTE]) {
|
||||||
|
status_debug("Grinding for to_remote (ours)");
|
||||||
|
/* We already tried `1` */
|
||||||
|
for (size_t csv = 2;
|
||||||
|
csv <= LEASE_RATE_DURATION;
|
||||||
|
csv++) {
|
||||||
|
|
||||||
|
script[REMOTE]
|
||||||
|
= scriptpubkey_to_remote(tmpctx,
|
||||||
|
&keyset->other_payment_key,
|
||||||
|
csv);
|
||||||
|
|
||||||
|
if (!wally_tx_output_scripteq(tx->outputs[i], script[REMOTE]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* BOLT #5:
|
||||||
|
*
|
||||||
|
* - MAY ignore the `to_remote` output.
|
||||||
|
* - Note: No action is required by the local
|
||||||
|
* node, as `to_remote` is considered *resolved*
|
||||||
|
* by the commitment transaction itself.
|
||||||
|
*/
|
||||||
|
out = new_tracked_output(&outs, &tx->txid, tx_blockheight,
|
||||||
|
OUR_UNILATERAL, i,
|
||||||
|
amt,
|
||||||
|
OUTPUT_TO_THEM,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
ignore_output(out);
|
||||||
|
script[REMOTE] = NULL;
|
||||||
|
add_amt(&their_outs, amt);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
continue;
|
||||||
|
|
||||||
onchain_annotate_txout(&tx->txid, i, TX_CHANNEL_PENALTY | TX_THEIRS);
|
onchain_annotate_txout(&tx->txid, i, TX_CHANNEL_PENALTY | TX_THEIRS);
|
||||||
status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
||||||
"Could not find resolution for output %zu",
|
"Could not find resolution for output %zu",
|
||||||
@@ -2919,7 +3012,8 @@ static void tell_wallet_to_remote(const struct tx_parts *tx,
|
|||||||
u32 tx_blockheight,
|
u32 tx_blockheight,
|
||||||
const u8 *scriptpubkey,
|
const u8 *scriptpubkey,
|
||||||
const struct pubkey *per_commit_point,
|
const struct pubkey *per_commit_point,
|
||||||
bool option_static_remotekey)
|
bool option_static_remotekey,
|
||||||
|
u32 csv_lock)
|
||||||
{
|
{
|
||||||
struct amount_asset asset = wally_tx_output_get_amount(tx->outputs[outnum]);
|
struct amount_asset asset = wally_tx_output_get_amount(tx->outputs[outnum]);
|
||||||
struct amount_sat amt;
|
struct amount_sat amt;
|
||||||
@@ -2971,6 +3065,47 @@ static void update_ledger_cheat(const struct bitcoin_txid *txid,
|
|||||||
blockheight, amt, true)));
|
blockheight, amt, true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void their_unilateral_local(struct tracked_output ***outs,
|
||||||
|
const struct tx_parts *tx,
|
||||||
|
u32 tx_blockheight,
|
||||||
|
size_t index,
|
||||||
|
struct amount_sat amt,
|
||||||
|
const u8 *local_scriptpubkey,
|
||||||
|
enum tx_type tx_type,
|
||||||
|
bool is_replay,
|
||||||
|
u32 csv_lock)
|
||||||
|
{
|
||||||
|
struct tracked_output *out;
|
||||||
|
/* 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,
|
||||||
|
&tx->txid,
|
||||||
|
tx_blockheight,
|
||||||
|
tx_type,
|
||||||
|
index, amt,
|
||||||
|
OUTPUT_TO_US,
|
||||||
|
NULL, NULL,
|
||||||
|
NULL);
|
||||||
|
ignore_output(out);
|
||||||
|
|
||||||
|
if (!is_replay)
|
||||||
|
record_channel_withdrawal(&tx->txid, tx_blockheight, out);
|
||||||
|
|
||||||
|
tell_wallet_to_remote(tx, index,
|
||||||
|
tx_blockheight,
|
||||||
|
local_scriptpubkey,
|
||||||
|
remote_per_commitment_point,
|
||||||
|
commit_num >= static_remotekey_start[REMOTE],
|
||||||
|
csv_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* BOLT #5:
|
/* BOLT #5:
|
||||||
*
|
*
|
||||||
* If any node tries to cheat by broadcasting an outdated commitment
|
* If any node tries to cheat by broadcasting an outdated commitment
|
||||||
@@ -2985,6 +3120,7 @@ static void handle_their_cheat(const struct tx_parts *tx,
|
|||||||
const struct htlc_stub *htlcs,
|
const struct htlc_stub *htlcs,
|
||||||
const bool *tell_if_missing,
|
const bool *tell_if_missing,
|
||||||
const bool *tell_immediately,
|
const bool *tell_immediately,
|
||||||
|
const enum side opener,
|
||||||
struct tracked_output **outs,
|
struct tracked_output **outs,
|
||||||
bool is_replay)
|
bool is_replay)
|
||||||
{
|
{
|
||||||
@@ -3140,28 +3276,10 @@ static void handle_their_cheat(const struct tx_parts *tx,
|
|||||||
if (script[LOCAL]
|
if (script[LOCAL]
|
||||||
&& wally_tx_output_scripteq(tx->outputs[i],
|
&& wally_tx_output_scripteq(tx->outputs[i],
|
||||||
script[LOCAL])) {
|
script[LOCAL])) {
|
||||||
/* BOLT #5:
|
their_unilateral_local(&outs, tx, tx_blockheight,
|
||||||
*
|
i, amt, script[LOCAL],
|
||||||
* - MAY take no action regarding the _local node's
|
THEIR_REVOKED_UNILATERAL,
|
||||||
* main output_, as this is a simple P2WPKH output
|
is_replay, 1);
|
||||||
* to itself.
|
|
||||||
* - Note: this output is considered *resolved* by
|
|
||||||
* the commitment transaction itself.
|
|
||||||
*/
|
|
||||||
out = new_tracked_output(&outs, &tx->txid, tx_blockheight,
|
|
||||||
THEIR_REVOKED_UNILATERAL,
|
|
||||||
i, amt,
|
|
||||||
OUTPUT_TO_US, NULL, NULL, NULL);
|
|
||||||
ignore_output(out);
|
|
||||||
|
|
||||||
if (!is_replay)
|
|
||||||
record_channel_withdrawal(&tx->txid, tx_blockheight, out);
|
|
||||||
|
|
||||||
tell_wallet_to_remote(tx, i,
|
|
||||||
tx_blockheight,
|
|
||||||
script[LOCAL],
|
|
||||||
remote_per_commitment_point,
|
|
||||||
commit_num >= static_remotekey_start[REMOTE]);
|
|
||||||
script[LOCAL] = NULL;
|
script[LOCAL] = NULL;
|
||||||
add_amt(&total_outs, amt);
|
add_amt(&total_outs, amt);
|
||||||
continue;
|
continue;
|
||||||
@@ -3214,7 +3332,71 @@ static void handle_their_cheat(const struct tx_parts *tx,
|
|||||||
|
|
||||||
matches = match_htlc_output(tmpctx, tx->outputs[i], htlc_scripts);
|
matches = match_htlc_output(tmpctx, tx->outputs[i], htlc_scripts);
|
||||||
if (tal_count(matches) == 0) {
|
if (tal_count(matches) == 0) {
|
||||||
status_broken("Could not find resolution for output %zu: did *we* cheat?", i);
|
bool found = false;
|
||||||
|
if (opener == REMOTE && script[LOCAL]) {
|
||||||
|
status_debug("Grinding for commitment to_remote"
|
||||||
|
" (ours)");
|
||||||
|
/* We already tried `1` */
|
||||||
|
for (size_t csv = 2;
|
||||||
|
csv <= LEASE_RATE_DURATION;
|
||||||
|
csv++) {
|
||||||
|
script[LOCAL]
|
||||||
|
= scriptpubkey_to_remote(tmpctx,
|
||||||
|
&keyset->other_payment_key,
|
||||||
|
csv);
|
||||||
|
if (!wally_tx_output_scripteq(
|
||||||
|
tx->outputs[i],
|
||||||
|
script[LOCAL]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
their_unilateral_local(&outs, tx,
|
||||||
|
tx_blockheight,
|
||||||
|
i, amt,
|
||||||
|
script[LOCAL],
|
||||||
|
THEIR_REVOKED_UNILATERAL,
|
||||||
|
is_replay,
|
||||||
|
csv);
|
||||||
|
script[LOCAL] = NULL;
|
||||||
|
add_amt(&total_outs, amt);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (opener == LOCAL && script[REMOTE]) {
|
||||||
|
status_debug("Grinding for commitment to_local"
|
||||||
|
" (theirs)");
|
||||||
|
for (size_t csv = 2;
|
||||||
|
csv <= LEASE_RATE_DURATION;
|
||||||
|
csv++) {
|
||||||
|
remote_wscript
|
||||||
|
= to_self_wscript(tmpctx,
|
||||||
|
to_self_delay[REMOTE],
|
||||||
|
csv, keyset);
|
||||||
|
script[REMOTE]
|
||||||
|
= scriptpubkey_p2wsh(tmpctx,
|
||||||
|
remote_wscript);
|
||||||
|
|
||||||
|
|
||||||
|
if (!wally_tx_output_scripteq(tx->outputs[i], script[REMOTE]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
out = new_tracked_output(&outs, &tx->txid, tx_blockheight,
|
||||||
|
THEIR_REVOKED_UNILATERAL, i,
|
||||||
|
amt,
|
||||||
|
DELAYED_CHEAT_OUTPUT_TO_THEM,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
steal_to_them_output(out, csv,
|
||||||
|
is_replay);
|
||||||
|
script[REMOTE] = NULL;
|
||||||
|
add_amt(&total_outs, amt);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
status_broken("Could not find resolution"
|
||||||
|
" for output %zu: did"
|
||||||
|
" *we* cheat?", i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3283,6 +3465,7 @@ static void handle_their_unilateral(const struct tx_parts *tx,
|
|||||||
const struct htlc_stub *htlcs,
|
const struct htlc_stub *htlcs,
|
||||||
const bool *tell_if_missing,
|
const bool *tell_if_missing,
|
||||||
const bool *tell_immediately,
|
const bool *tell_immediately,
|
||||||
|
const enum side opener,
|
||||||
struct tracked_output **outs,
|
struct tracked_output **outs,
|
||||||
bool is_replay)
|
bool is_replay)
|
||||||
{
|
{
|
||||||
@@ -3368,26 +3551,9 @@ static void handle_their_unilateral(const struct tx_parts *tx,
|
|||||||
type_to_string(tmpctx, struct pubkey,
|
type_to_string(tmpctx, struct pubkey,
|
||||||
&keyset->other_htlc_key));
|
&keyset->other_htlc_key));
|
||||||
|
|
||||||
remote_wscript = to_self_wscript(tmpctx, to_self_delay[REMOTE],
|
|
||||||
1, keyset);
|
|
||||||
|
|
||||||
/* Figure out what to-them output looks like. */
|
|
||||||
script[REMOTE] = scriptpubkey_p2wsh(tmpctx, remote_wscript);
|
|
||||||
|
|
||||||
/* Figure out what direct to-us output looks like. */
|
|
||||||
script[LOCAL] = scriptpubkey_to_remote(tmpctx,
|
|
||||||
&keyset->other_payment_key, 1);
|
|
||||||
|
|
||||||
/* Calculate all the HTLC scripts so we can match them */
|
/* Calculate all the HTLC scripts so we can match them */
|
||||||
htlc_scripts = derive_htlc_scripts(htlcs, REMOTE);
|
htlc_scripts = derive_htlc_scripts(htlcs, REMOTE);
|
||||||
|
|
||||||
status_debug("Script to-them: %u: %s (%s)",
|
|
||||||
to_self_delay[REMOTE],
|
|
||||||
tal_hex(tmpctx, script[REMOTE]),
|
|
||||||
tal_hex(tmpctx, remote_wscript));
|
|
||||||
status_debug("Script to-me: %s",
|
|
||||||
tal_hex(tmpctx, script[LOCAL]));
|
|
||||||
|
|
||||||
get_anchor_scriptpubkeys(tmpctx, anchor);
|
get_anchor_scriptpubkeys(tmpctx, anchor);
|
||||||
|
|
||||||
for (i = 0; i < tal_count(tx->outputs); i++) {
|
for (i = 0; i < tal_count(tx->outputs); i++) {
|
||||||
@@ -3398,6 +3564,21 @@ static void handle_their_unilateral(const struct tx_parts *tx,
|
|||||||
tx->outputs[i]->script_len));
|
tx->outputs[i]->script_len));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
remote_wscript = to_self_wscript(tmpctx, to_self_delay[REMOTE],
|
||||||
|
1, keyset);
|
||||||
|
script[REMOTE] = scriptpubkey_p2wsh(tmpctx, remote_wscript);
|
||||||
|
|
||||||
|
script[LOCAL] = scriptpubkey_to_remote(tmpctx,
|
||||||
|
&keyset->other_payment_key,
|
||||||
|
1);
|
||||||
|
|
||||||
|
status_debug("Script to-them: %u: %s (%s)",
|
||||||
|
to_self_delay[REMOTE],
|
||||||
|
tal_hex(tmpctx, script[REMOTE]),
|
||||||
|
tal_hex(tmpctx, remote_wscript));
|
||||||
|
status_debug("Script to-me: %s",
|
||||||
|
tal_hex(tmpctx, script[LOCAL]));
|
||||||
|
|
||||||
for (i = 0; i < tal_count(tx->outputs); i++) {
|
for (i = 0; i < tal_count(tx->outputs); i++) {
|
||||||
struct tracked_output *out;
|
struct tracked_output *out;
|
||||||
const size_t *matches;
|
const size_t *matches;
|
||||||
@@ -3421,28 +3602,11 @@ static void handle_their_unilateral(const struct tx_parts *tx,
|
|||||||
} else if (script[LOCAL]
|
} else if (script[LOCAL]
|
||||||
&& wally_tx_output_scripteq(tx->outputs[i],
|
&& wally_tx_output_scripteq(tx->outputs[i],
|
||||||
script[LOCAL])) {
|
script[LOCAL])) {
|
||||||
/* BOLT #5:
|
their_unilateral_local(&outs, tx, tx_blockheight,
|
||||||
*
|
i, amt, script[LOCAL],
|
||||||
* - MAY take no action in regard to the associated
|
THEIR_UNILATERAL,
|
||||||
* `to_remote`, which is simply a P2WPKH output to
|
is_replay, 1);
|
||||||
* the *local node*.
|
|
||||||
* - Note: `to_remote` is considered *resolved* by the
|
|
||||||
* commitment transaction itself.
|
|
||||||
*/
|
|
||||||
out = new_tracked_output(&outs, &tx->txid, tx_blockheight,
|
|
||||||
THEIR_UNILATERAL,
|
|
||||||
i, amt,
|
|
||||||
OUTPUT_TO_US, NULL, NULL, NULL);
|
|
||||||
ignore_output(out);
|
|
||||||
|
|
||||||
if (!is_replay)
|
|
||||||
record_channel_withdrawal(&tx->txid, tx_blockheight, out);
|
|
||||||
|
|
||||||
tell_wallet_to_remote(tx, i,
|
|
||||||
tx_blockheight,
|
|
||||||
script[LOCAL],
|
|
||||||
remote_per_commitment_point,
|
|
||||||
commit_num >= static_remotekey_start[REMOTE]);
|
|
||||||
script[LOCAL] = NULL;
|
script[LOCAL] = NULL;
|
||||||
add_amt(&our_outs, amt);
|
add_amt(&our_outs, amt);
|
||||||
continue;
|
continue;
|
||||||
@@ -3496,10 +3660,75 @@ static void handle_their_unilateral(const struct tx_parts *tx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
matches = match_htlc_output(tmpctx, tx->outputs[i], htlc_scripts);
|
matches = match_htlc_output(tmpctx, tx->outputs[i], htlc_scripts);
|
||||||
if (tal_count(matches) == 0)
|
if (tal_count(matches) == 0) {
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
/* We need to hunt for it (option_will_fund?) */
|
||||||
|
if (opener == REMOTE && script[LOCAL]) {
|
||||||
|
status_debug("Grinding for commitment to_remote"
|
||||||
|
" (ours)");
|
||||||
|
/* We already tried `1` */
|
||||||
|
for (size_t csv = 2;
|
||||||
|
csv <= LEASE_RATE_DURATION;
|
||||||
|
csv++) {
|
||||||
|
script[LOCAL]
|
||||||
|
= scriptpubkey_to_remote(tmpctx,
|
||||||
|
&keyset->other_payment_key,
|
||||||
|
csv);
|
||||||
|
if (!wally_tx_output_scripteq(
|
||||||
|
tx->outputs[i],
|
||||||
|
script[LOCAL]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
their_unilateral_local(&outs, tx,
|
||||||
|
tx_blockheight,
|
||||||
|
i, amt,
|
||||||
|
script[LOCAL],
|
||||||
|
THEIR_UNILATERAL,
|
||||||
|
is_replay, csv);
|
||||||
|
script[LOCAL] = NULL;
|
||||||
|
add_amt(&our_outs, amt);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (opener == LOCAL && script[REMOTE]) {
|
||||||
|
status_debug("Grinding for commitment to_local"
|
||||||
|
" (theirs)");
|
||||||
|
/* We already tried `1` */
|
||||||
|
for (size_t csv = 2;
|
||||||
|
csv <= LEASE_RATE_DURATION;
|
||||||
|
csv++) {
|
||||||
|
remote_wscript
|
||||||
|
= to_self_wscript(tmpctx,
|
||||||
|
to_self_delay[REMOTE],
|
||||||
|
csv, keyset);
|
||||||
|
script[REMOTE]
|
||||||
|
= scriptpubkey_p2wsh(tmpctx,
|
||||||
|
remote_wscript);
|
||||||
|
|
||||||
|
|
||||||
|
if (!wally_tx_output_scripteq(tx->outputs[i], script[REMOTE]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
out = new_tracked_output(&outs, &tx->txid, tx_blockheight,
|
||||||
|
THEIR_UNILATERAL, i,
|
||||||
|
amt,
|
||||||
|
DELAYED_OUTPUT_TO_THEM,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
ignore_output(out);
|
||||||
|
add_amt(&their_outs, amt);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
continue;
|
||||||
|
|
||||||
status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
||||||
"Could not find resolution for output %zu",
|
"Could not find resolution for output %zu",
|
||||||
i);
|
i);
|
||||||
|
}
|
||||||
|
|
||||||
if (matches_direction(matches, htlcs) == LOCAL) {
|
if (matches_direction(matches, htlcs) == LOCAL) {
|
||||||
/* BOLT #5:
|
/* BOLT #5:
|
||||||
@@ -3629,59 +3858,66 @@ static void handle_unknown_commitment(const struct tx_parts *tx,
|
|||||||
local_scripts[0] = NULL;
|
local_scripts[0] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Other possible local script is for option_static_remotekey */
|
/* For option_will_fund, we need to figure out what CSV lock was used */
|
||||||
local_scripts[1] = scriptpubkey_to_remote(tmpctx,
|
for (size_t csv = 1; csv <= LEASE_RATE_DURATION; csv++) {
|
||||||
&basepoints[LOCAL].payment,
|
|
||||||
1);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < tal_count(tx->outputs); i++) {
|
/* Other possible local script is for option_static_remotekey */
|
||||||
struct tracked_output *out;
|
local_scripts[1] = scriptpubkey_to_remote(tmpctx,
|
||||||
struct amount_asset asset = wally_tx_output_get_amount(tx->outputs[i]);
|
&basepoints[LOCAL].payment,
|
||||||
struct amount_sat amt;
|
csv);
|
||||||
int which_script;
|
|
||||||
|
|
||||||
assert(amount_asset_is_main(&asset));
|
for (size_t i = 0; i < tal_count(tx->outputs); i++) {
|
||||||
amt = amount_asset_to_sat(&asset);
|
struct tracked_output *out;
|
||||||
|
struct amount_asset asset = wally_tx_output_get_amount(tx->outputs[i]);
|
||||||
|
struct amount_sat amt;
|
||||||
|
int which_script;
|
||||||
|
|
||||||
/* Elements can have empty output scripts (fee output) */
|
assert(amount_asset_is_main(&asset));
|
||||||
if (local_scripts[0]
|
amt = amount_asset_to_sat(&asset);
|
||||||
&& wally_tx_output_scripteq(tx->outputs[i], local_scripts[0]))
|
|
||||||
which_script = 0;
|
|
||||||
else if (local_scripts[1]
|
|
||||||
&& wally_tx_output_scripteq(tx->outputs[i],
|
|
||||||
local_scripts[1]))
|
|
||||||
which_script = 1;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* BOLT #5:
|
/* Elements can have empty output scripts (fee output) */
|
||||||
*
|
if (local_scripts[0]
|
||||||
* - MAY take no action in regard to the associated
|
&& wally_tx_output_scripteq(tx->outputs[i], local_scripts[0]))
|
||||||
* `to_remote`, which is simply a P2WPKH output to
|
which_script = 0;
|
||||||
* the *local node*.
|
else if (local_scripts[1]
|
||||||
* - Note: `to_remote` is considered *resolved* by the
|
&& wally_tx_output_scripteq(tx->outputs[i],
|
||||||
* commitment transaction itself.
|
local_scripts[1]))
|
||||||
*/
|
which_script = 1;
|
||||||
out = new_tracked_output(&outs, &tx->txid, tx_blockheight,
|
else
|
||||||
UNKNOWN_UNILATERAL,
|
continue;
|
||||||
i, amt,
|
|
||||||
OUTPUT_TO_US, NULL, NULL, NULL);
|
|
||||||
ignore_output(out);
|
|
||||||
|
|
||||||
if (!is_replay)
|
/* BOLT #5:
|
||||||
record_channel_withdrawal(&tx->txid, tx_blockheight, out);
|
*
|
||||||
|
* - 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, &tx->txid, tx_blockheight,
|
||||||
|
UNKNOWN_UNILATERAL,
|
||||||
|
i, amt,
|
||||||
|
OUTPUT_TO_US, NULL, NULL, NULL);
|
||||||
|
ignore_output(out);
|
||||||
|
|
||||||
add_amt(&amt_salvaged, amt);
|
if (!is_replay)
|
||||||
|
record_channel_withdrawal(&tx->txid, tx_blockheight, out);
|
||||||
|
|
||||||
tell_wallet_to_remote(tx, i,
|
add_amt(&amt_salvaged, amt);
|
||||||
tx_blockheight,
|
|
||||||
local_scripts[which_script],
|
tell_wallet_to_remote(tx, i,
|
||||||
possible_remote_per_commitment_point,
|
tx_blockheight,
|
||||||
which_script == 1);
|
local_scripts[which_script],
|
||||||
local_scripts[0] = local_scripts[1] = NULL;
|
possible_remote_per_commitment_point,
|
||||||
to_us_output = i;
|
which_script == 1,
|
||||||
|
csv);
|
||||||
|
local_scripts[0] = local_scripts[1] = NULL;
|
||||||
|
to_us_output = i;
|
||||||
|
goto script_found;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
script_found:
|
||||||
if (to_us_output == -1) {
|
if (to_us_output == -1) {
|
||||||
status_broken("FUNDS LOST. Unknown commitment #%"PRIu64"!",
|
status_broken("FUNDS LOST. Unknown commitment #%"PRIu64"!",
|
||||||
commit_num);
|
commit_num);
|
||||||
@@ -3870,6 +4106,7 @@ int main(int argc, char *argv[])
|
|||||||
basepoints,
|
basepoints,
|
||||||
htlcs,
|
htlcs,
|
||||||
tell_if_missing, tell_immediately,
|
tell_if_missing, tell_immediately,
|
||||||
|
opener,
|
||||||
remote_htlc_sigs,
|
remote_htlc_sigs,
|
||||||
outs,
|
outs,
|
||||||
open_is_replay);
|
open_is_replay);
|
||||||
@@ -3888,6 +4125,7 @@ int main(int argc, char *argv[])
|
|||||||
basepoints,
|
basepoints,
|
||||||
htlcs,
|
htlcs,
|
||||||
tell_if_missing, tell_immediately,
|
tell_if_missing, tell_immediately,
|
||||||
|
opener,
|
||||||
outs,
|
outs,
|
||||||
open_is_replay);
|
open_is_replay);
|
||||||
/* BOLT #5:
|
/* BOLT #5:
|
||||||
@@ -3907,6 +4145,7 @@ int main(int argc, char *argv[])
|
|||||||
htlcs,
|
htlcs,
|
||||||
tell_if_missing,
|
tell_if_missing,
|
||||||
tell_immediately,
|
tell_immediately,
|
||||||
|
opener,
|
||||||
outs,
|
outs,
|
||||||
open_is_replay);
|
open_is_replay);
|
||||||
} else if (commit_num == revocations_received(&shachain) + 1) {
|
} else if (commit_num == revocations_received(&shachain) + 1) {
|
||||||
@@ -3917,6 +4156,7 @@ int main(int argc, char *argv[])
|
|||||||
htlcs,
|
htlcs,
|
||||||
tell_if_missing,
|
tell_if_missing,
|
||||||
tell_immediately,
|
tell_immediately,
|
||||||
|
opener,
|
||||||
outs,
|
outs,
|
||||||
open_is_replay);
|
open_is_replay);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user