From c9d27480814ab98d337ae2ddef98f3b36be5f1df Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 16 Jun 2021 12:44:51 -0500 Subject: [PATCH] lease_rates: add csv lock to modify anchor scripts --- bitcoin/script.c | 39 +++++++++++++++++++++++---- bitcoin/script.h | 6 ++--- channeld/commit_tx.c | 6 ++++- channeld/watchtower.c | 3 ++- common/initial_channel.c | 1 + common/initial_commit_tx.c | 10 ++++--- common/initial_commit_tx.h | 2 ++ hsmd/libhsmd.c | 5 +++- onchaind/onchaind.c | 20 ++++++++------ onchaind/test/run-grind_feerate-bug.c | 1 + onchaind/test/run-grind_feerate.c | 1 + 11 files changed, 72 insertions(+), 22 deletions(-) diff --git a/bitcoin/script.c b/bitcoin/script.c index cbf45858b..d4b7db962 100644 --- a/bitcoin/script.c +++ b/bitcoin/script.c @@ -14,6 +14,8 @@ /* To push 0-75 bytes onto stack. */ #define OP_PUSHBYTES(val) (val) +#define max(a, b) ((a) > (b) ? (a) : (b)) + /* Bitcoin's OP_HASH160 is RIPEMD(SHA256()) */ static void hash160(struct ripemd160 *redeemhash, const void *mem, size_t len) { @@ -353,15 +355,21 @@ u8 *anchor_to_remote_redeem(const tal_t *ctx, bool is_anchor_witness_script(const u8 *script, size_t script_len) { - if (script_len != 34 + 1 + 1 + 1) + size_t len = 34 + 1 + 1 + 1; + /* With option_will_fund, the pushbytes can be up to 2 bytes more + * + * OP_CHECKSIGVERIFY + * MAX(1, lease_end - blockheight) + * OP_CHECKSEQUENCEVERIFY + */ + if (script_len < len || script_len > len + 2) return false; if (script[0] != OP_PUSHBYTES(33)) return false; if (script[34] != OP_CHECKSIGVERIFY) return false; - if (script[35] != 0x51) - return false; - if (script[36] != OP_CHECKSEQUENCEVERIFY) + /* FIXME: check for push value */ + if (script[script_len - 1] != OP_CHECKSEQUENCEVERIFY) return false; return true; } @@ -521,7 +529,28 @@ u8 **bitcoin_witness_sig_and_element(const tal_t *ctx, * OP_ENDIF * OP_CHECKSIG */ +/* BOLT- #3 + * ##### Leased channel (`option_will_fund`) + * If a `lease` applies to the channel, the `to_local` output of the `accepter` + * ensures the `leasor` funds are not spendable until the lease expires. + * + * In a leased channel, the `to_local` output that pays the `accepter` node + * is modified so that its CSV is equal to the greater of the + * `to_self_delay` or the `lease_end` - `blockheight`. + * + * OP_IF + * # Penalty transaction + * + * OP_ELSE + * MAX(`to_self_delay`, `lease_end` - `blockheight`) + * OP_CHECKSEQUENCEVERIFY + * OP_DROP + * + * OP_ENDIF + * OP_CHECKSIG + */ u8 *bitcoin_wscript_to_local(const tal_t *ctx, u16 to_self_delay, + u32 lease_remaining, const struct pubkey *revocation_pubkey, const struct pubkey *local_delayedkey) { @@ -529,7 +558,7 @@ u8 *bitcoin_wscript_to_local(const tal_t *ctx, u16 to_self_delay, add_op(&script, OP_IF); add_push_key(&script, revocation_pubkey); add_op(&script, OP_ELSE); - add_number(&script, to_self_delay); + add_number(&script, max(lease_remaining, to_self_delay)); add_op(&script, OP_CHECKSEQUENCEVERIFY); add_op(&script, OP_DROP); add_push_key(&script, local_delayedkey); diff --git a/bitcoin/script.h b/bitcoin/script.h index 351bbcda0..807bd830e 100644 --- a/bitcoin/script.h +++ b/bitcoin/script.h @@ -67,7 +67,7 @@ u8 *scriptpubkey_p2wpkh_derkey(const tal_t *ctx, const u8 der[33]); u8 *scriptpubkey_witness_raw(const tal_t *ctx, u8 version, const u8 *wprog, size_t wprog_size); -/* To-remotekey with csv 1 delay. */ +/* To-remotekey with csv max(lease_expiry - blockheight, 1) delay. */ u8 *anchor_to_remote_redeem(const tal_t *ctx, const struct pubkey *remote_key, u32 csv_lock); @@ -91,8 +91,8 @@ u8 **bitcoin_witness_sig_and_element(const tal_t *ctx, const u8 *witnessscript); /* BOLT #3 to-local output */ -u8 *bitcoin_wscript_to_local(const tal_t *ctx, - u16 to_self_delay, +u8 *bitcoin_wscript_to_local(const tal_t *ctx, u16 to_self_delay, + u32 lease_remaining, const struct pubkey *revocation_pubkey, const struct pubkey *local_delayedkey); diff --git a/channeld/commit_tx.c b/channeld/commit_tx.c index 77ad07c0b..045f1a833 100644 --- a/channeld/commit_tx.c +++ b/channeld/commit_tx.c @@ -234,7 +234,10 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, * output](#to_local-output). */ if (amount_msat_greater_eq_sat(self_pay, dust_limit)) { - u8 *wscript = to_self_wscript(tmpctx, to_self_delay,keyset); + u8 *wscript = to_self_wscript(tmpctx, + to_self_delay, + 1, /* FIXME: csv_lock */ + keyset); u8 *p2wsh = scriptpubkey_p2wsh(tx, wscript); struct amount_sat amount = amount_msat_to_sat_round_down(self_pay); @@ -275,6 +278,7 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, * Otherwise, this output is a simple P2WPKH to `remotepubkey`. */ if (option_anchor_outputs) { + /* FIXME: use csv_lock */ scriptpubkey = scriptpubkey_p2wsh(tmpctx, anchor_to_remote_redeem(tmpctx, &keyset->other_payment_key, 1)); } else { diff --git a/channeld/watchtower.c b/channeld/watchtower.c index ded35186e..994f643d0 100644 --- a/channeld/watchtower.c +++ b/channeld/watchtower.c @@ -63,7 +63,8 @@ penalty_tx_create(const tal_t *ctx, status_failed(STATUS_FAIL_INTERNAL_ERROR, "Failed deriving keyset"); - wscript = bitcoin_wscript_to_local(tmpctx, remote_to_self_delay, + /* FIXME: csv_lock */ + wscript = bitcoin_wscript_to_local(tmpctx, remote_to_self_delay, 1, &keyset.self_revocation_key, &keyset.self_delayed_payment_key); diff --git a/common/initial_channel.c b/common/initial_channel.c index fb01cd175..15b59f306 100644 --- a/common/initial_channel.c +++ b/common/initial_channel.c @@ -120,6 +120,7 @@ struct bitcoin_tx *initial_channel_tx(const tal_t *ctx, 0 ^ channel->commitment_number_obscurer, direct_outputs, side, + 0, /* FIXME: csv lock? */ channel->option_anchor_outputs, err_reason); diff --git a/common/initial_commit_tx.c b/common/initial_commit_tx.c index 792b32be4..593eaa5cc 100644 --- a/common/initial_commit_tx.c +++ b/common/initial_commit_tx.c @@ -51,9 +51,10 @@ bool try_subtract_fee(enum side opener, enum side side, u8 *to_self_wscript(const tal_t *ctx, u16 to_self_delay, + u32 csv, const struct keyset *keyset) { - return bitcoin_wscript_to_local(ctx, to_self_delay, + return bitcoin_wscript_to_local(ctx, to_self_delay, csv, &keyset->self_revocation_key, &keyset->self_delayed_payment_key); } @@ -87,6 +88,7 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx, u64 obscured_commitment_number, struct wally_tx_output *direct_outputs[NUM_SIDES], enum side side, + u32 csv_lock, bool option_anchor_outputs, char** err_reason) { @@ -208,7 +210,9 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx, * output](#to_local-output). */ if (amount_msat_greater_eq_sat(self_pay, dust_limit)) { - u8 *wscript = to_self_wscript(tmpctx, to_self_delay, keyset); + u8 *wscript = to_self_wscript(tmpctx, + to_self_delay, csv_lock, + keyset); amount = amount_msat_to_sat_round_down(self_pay); int pos = bitcoin_tx_add_output( tx, scriptpubkey_p2wsh(tx, wscript), wscript, amount); @@ -242,7 +246,7 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx, amount = amount_msat_to_sat_round_down(other_pay); if (option_anchor_outputs) { scriptpubkey = scriptpubkey_p2wsh(tmpctx, - anchor_to_remote_redeem(tmpctx, &keyset->other_payment_key, 1)); + anchor_to_remote_redeem(tmpctx, &keyset->other_payment_key, csv_lock)); } else { scriptpubkey = scriptpubkey_p2wpkh(tmpctx, &keyset->other_payment_key); diff --git a/common/initial_commit_tx.h b/common/initial_commit_tx.h index 8ff4b0155..90f7dbda4 100644 --- a/common/initial_commit_tx.h +++ b/common/initial_commit_tx.h @@ -121,6 +121,7 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx, u64 obscured_commitment_number, struct wally_tx_output *direct_outputs[NUM_SIDES], enum side side, + u32 csv_lock, bool option_anchor_outputs, char** err_reason); @@ -134,6 +135,7 @@ bool try_subtract_fee(enum side opener, enum side side, * scriptpubkey_p2wsh(ctx, wscript) gives the scriptpubkey */ u8 *to_self_wscript(const tal_t *ctx, u16 to_self_delay, + u32 csv, const struct keyset *keyset); /* To-other is simply: scriptpubkey_p2wpkh(tx, keyset->other_payment_key) */ diff --git a/hsmd/libhsmd.c b/hsmd/libhsmd.c index 5d026fbe5..b51433b55 100644 --- a/hsmd/libhsmd.c +++ b/hsmd/libhsmd.c @@ -388,7 +388,10 @@ static void sign_our_inputs(struct utxo **utxos, struct wally_psbt *psbt) /* It's actually a P2WSH in this case. */ if (utxo->close_info && utxo->close_info->option_anchor_outputs) { - const u8 *wscript = anchor_to_remote_redeem(tmpctx, &pubkey, 1); + const u8 *wscript + = anchor_to_remote_redeem(tmpctx, + &pubkey, + 1); /* FIXME: lease csv ? */ psbt_input_set_witscript(psbt, j, wscript); psbt_input_set_wit_utxo(psbt, j, scriptpubkey_p2wsh(psbt, wscript), diff --git a/onchaind/onchaind.c b/onchaind/onchaind.c index 2cc8f01f3..71f56981d 100644 --- a/onchaind/onchaind.c +++ b/onchaind/onchaind.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -2644,15 +2645,15 @@ static void handle_our_unilateral(const struct tx_parts *tx, type_to_string(tmpctx, struct pubkey, &keyset->other_htlc_key)); - local_wscript = to_self_wscript(tmpctx, to_self_delay[LOCAL], keyset); + local_wscript = to_self_wscript(tmpctx, to_self_delay[LOCAL], + 1, keyset); /* Figure out what to-us output looks like. */ script[LOCAL] = scriptpubkey_p2wsh(tmpctx, local_wscript); /* Figure out what direct to-them output looks like. */ script[REMOTE] = scriptpubkey_to_remote(tmpctx, - &keyset->other_payment_key, - 1); + &keyset->other_payment_key, 1); /* Calculate all the HTLC scripts so we can match them */ htlc_scripts = derive_htlc_scripts(htlcs, LOCAL); @@ -2866,7 +2867,8 @@ static void handle_our_unilateral(const struct tx_parts *tx, /* 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, bool is_replay) +static void steal_to_them_output(struct tracked_output *out, + u32 csv, bool is_replay) { u8 *wscript; struct bitcoin_tx *tx; @@ -2879,7 +2881,7 @@ static void steal_to_them_output(struct tracked_output *out, bool is_replay) * * 1 */ - wscript = bitcoin_wscript_to_local(tmpctx, to_self_delay[REMOTE], + wscript = bitcoin_wscript_to_local(tmpctx, to_self_delay[REMOTE], csv, &keyset->self_revocation_key, &keyset->self_delayed_payment_key); @@ -3083,7 +3085,8 @@ static void handle_their_cheat(const struct tx_parts *tx, static_remotekey_start[LOCAL], static_remotekey_start[REMOTE]); - remote_wscript = to_self_wscript(tmpctx, to_self_delay[REMOTE], keyset); + 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); @@ -3176,7 +3179,7 @@ static void handle_their_cheat(const struct tx_parts *tx, amt, DELAYED_CHEAT_OUTPUT_TO_THEM, NULL, NULL, NULL); - steal_to_them_output(out, is_replay); + steal_to_them_output(out, 1, is_replay); script[REMOTE] = NULL; add_amt(&total_outs, amt); continue; @@ -3365,7 +3368,8 @@ static void handle_their_unilateral(const struct tx_parts *tx, type_to_string(tmpctx, struct pubkey, &keyset->other_htlc_key)); - remote_wscript = to_self_wscript(tmpctx, to_self_delay[REMOTE], keyset); + 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); diff --git a/onchaind/test/run-grind_feerate-bug.c b/onchaind/test/run-grind_feerate-bug.c index f6a77c2ec..8c44c52ed 100644 --- a/onchaind/test/run-grind_feerate-bug.c +++ b/onchaind/test/run-grind_feerate-bug.c @@ -213,6 +213,7 @@ void subdaemon_setup(int argc UNNEEDED, char *argv[]) /* Generated stub for to_self_wscript */ u8 *to_self_wscript(const tal_t *ctx UNNEEDED, u16 to_self_delay UNNEEDED, + u32 csv UNNEEDED, const struct keyset *keyset UNNEEDED) { fprintf(stderr, "to_self_wscript called!\n"); abort(); } /* Generated stub for towire */ diff --git a/onchaind/test/run-grind_feerate.c b/onchaind/test/run-grind_feerate.c index 0a9b3d4ca..c89ecef9e 100644 --- a/onchaind/test/run-grind_feerate.c +++ b/onchaind/test/run-grind_feerate.c @@ -230,6 +230,7 @@ void subdaemon_setup(int argc UNNEEDED, char *argv[]) /* Generated stub for to_self_wscript */ u8 *to_self_wscript(const tal_t *ctx UNNEEDED, u16 to_self_delay UNNEEDED, + u32 csv UNNEEDED, const struct keyset *keyset UNNEEDED) { fprintf(stderr, "to_self_wscript called!\n"); abort(); } /* Generated stub for towire */