Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zero fee htlc: Finally add support (experimental!) #6137

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .msggen.json
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@
"Feerates.perkb.mutual_close": 4,
"Feerates.perkb.opening": 3,
"Feerates.perkb.penalty": 8,
"Feerates.perkb.unilateral_anchor_close": 11,
"Feerates.perkb.unilateral_close": 5
},
"FeeratesPerkbEstimates": {
Expand Down Expand Up @@ -1602,6 +1603,10 @@
"added": "pre-v0.10.1",
"deprecated": false
},
"Feerates.perkb.unilateral_anchor_close": {
"added": "v23.05",
"deprecated": false
},
"Feerates.perkb.unilateral_close": {
"added": "pre-v0.10.1",
"deprecated": false
Expand Down
26 changes: 23 additions & 3 deletions bitcoin/psbt.c
Original file line number Diff line number Diff line change
Expand Up @@ -603,18 +603,24 @@ bool psbt_finalize(struct wally_psbt *psbt)
tal_wally_start();

/* Wally doesn't know how to finalize P2WSH; this happens with
* option_anchor_outputs, and finalizing is trivial. */
* option_anchor_outputs, and finalizing those two cases is trivial. */
/* FIXME: miniscript! miniscript! miniscript! */
for (size_t i = 0; i < psbt->num_inputs; i++) {
struct wally_psbt_input *input = &psbt->inputs[i];
struct wally_tx_witness_stack *stack;
const struct wally_map_item *iws;

iws = wally_map_get_integer(&input->psbt_fields, /* PSBT_IN_WITNESS_SCRIPT */ 0x05);
if (!iws || !is_to_remote_anchored_witness_script(iws->value,
iws->value_len))
if (!iws)
continue;

if (!is_to_remote_anchored_witness_script(iws->value,
iws->value_len)
&& !is_anchor_witness_script(iws->value,
iws->value_len)) {
continue;
}

if (input->signatures.num_items != 1)
continue;

Expand All @@ -632,6 +638,19 @@ bool psbt_finalize(struct wally_psbt *psbt)
*
* <remote_sig>
*/
/* BOLT #3:
* #### `to_local_anchor` and `to_remote_anchor` Output (option_anchors)
*...
* <local_funding_pubkey/remote_funding_pubkey> OP_CHECKSIG OP_IFDUP
* OP_NOTIF
* OP_16 OP_CHECKSEQUENCEVERIFY
* OP_ENDIF
*...
* Spending of the output requires the following witness:
* <local_sig/remote_sig>
*/

/* i.e. in both cases, this is the same thing */
wally_tx_witness_stack_init_alloc(2, &stack);
wally_tx_witness_stack_add(stack,
input->signatures.items[0].value,
Expand All @@ -640,6 +659,7 @@ bool psbt_finalize(struct wally_psbt *psbt)
iws->value,
iws->value_len);
wally_psbt_input_set_final_witness(input, stack);
wally_tx_witness_stack_free(stack);
}

ok = (wally_psbt_finalize(psbt) == WALLY_OK);
Expand Down
44 changes: 36 additions & 8 deletions bitcoin/script.c
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,8 @@ u8 *bitcoin_wscript_htlc_offer_ripemd160(const tal_t *ctx,
const struct pubkey *remotehtlckey,
const struct ripemd160 *payment_ripemd,
const struct pubkey *revocationkey,
bool option_anchor_outputs)
bool option_anchor_outputs,
bool option_anchors_zero_fee_htlc_tx)
{
u8 *script = tal_arr(ctx, u8, 0);
struct ripemd160 ripemd;
Expand Down Expand Up @@ -638,7 +639,7 @@ u8 *bitcoin_wscript_htlc_offer_ripemd160(const tal_t *ctx,
add_op(&script, OP_EQUALVERIFY);
add_op(&script, OP_CHECKSIG);
add_op(&script, OP_ENDIF);
if (option_anchor_outputs) {
if (option_anchor_outputs || option_anchors_zero_fee_htlc_tx) {
add_number(&script, 1);
add_op(&script, OP_CHECKSEQUENCEVERIFY);
add_op(&script, OP_DROP);
Expand All @@ -653,15 +654,17 @@ u8 *bitcoin_wscript_htlc_offer(const tal_t *ctx,
const struct pubkey *remotehtlckey,
const struct sha256 *payment_hash,
const struct pubkey *revocationkey,
bool option_anchor_outputs)
bool option_anchor_outputs,
bool option_anchors_zero_fee_htlc_tx)
{
struct ripemd160 ripemd;

ripemd160(&ripemd, payment_hash->u.u8, sizeof(payment_hash->u));
return bitcoin_wscript_htlc_offer_ripemd160(ctx, localhtlckey,
remotehtlckey,
&ripemd, revocationkey,
option_anchor_outputs);
option_anchor_outputs,
option_anchors_zero_fee_htlc_tx);
}

/* BOLT #3:
Expand Down Expand Up @@ -717,7 +720,8 @@ u8 *bitcoin_wscript_htlc_receive_ripemd(const tal_t *ctx,
const struct pubkey *remotehtlckey,
const struct ripemd160 *payment_ripemd,
const struct pubkey *revocationkey,
bool option_anchor_outputs)
bool option_anchor_outputs,
bool option_anchors_zero_fee_htlc_tx)
{
u8 *script = tal_arr(ctx, u8, 0);
struct ripemd160 ripemd;
Expand Down Expand Up @@ -752,7 +756,7 @@ u8 *bitcoin_wscript_htlc_receive_ripemd(const tal_t *ctx,
add_op(&script, OP_DROP);
add_op(&script, OP_CHECKSIG);
add_op(&script, OP_ENDIF);
if (option_anchor_outputs) {
if (option_anchor_outputs || option_anchors_zero_fee_htlc_tx) {
add_number(&script, 1);
add_op(&script, OP_CHECKSEQUENCEVERIFY);
add_op(&script, OP_DROP);
Expand All @@ -768,15 +772,17 @@ u8 *bitcoin_wscript_htlc_receive(const tal_t *ctx,
const struct pubkey *remotehtlckey,
const struct sha256 *payment_hash,
const struct pubkey *revocationkey,
bool option_anchor_outputs)
bool option_anchor_outputs,
bool option_anchors_zero_fee_htlc_tx)
{
struct ripemd160 ripemd;

ripemd160(&ripemd, payment_hash->u.u8, sizeof(payment_hash->u));
return bitcoin_wscript_htlc_receive_ripemd(ctx, htlc_abstimeout,
localhtlckey, remotehtlckey,
&ripemd, revocationkey,
option_anchor_outputs);
option_anchor_outputs,
option_anchors_zero_fee_htlc_tx);
}

/* BOLT #3:
Expand Down Expand Up @@ -874,9 +880,31 @@ u8 *bitcoin_wscript_anchor(const tal_t *ctx,
add_op(&script, OP_CHECKSEQUENCEVERIFY);
add_op(&script, OP_ENDIF);

assert(is_anchor_witness_script(script, tal_bytelen(script)));
return script;
}

bool is_anchor_witness_script(const u8 *script, size_t script_len)
{
if (script_len != 34 + 1 + 1 + 1 + 1 + 1 + 1)
return false;
if (script[0] != OP_PUSHBYTES(33))
return false;
if (script[34] != OP_CHECKSIG)
return false;
if (script[35] != OP_IFDUP)
return false;
if (script[36] != OP_NOTIF)
return false;
if (script[37] != 0x50 + 16)
return false;
if (script[38] != OP_CHECKSEQUENCEVERIFY)
return false;
if (script[39] != OP_ENDIF)
return false;
return true;
Comment on lines +889 to +905
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A template comparison system would be nice here, but probably overkill 🤔

}

bool scripteq(const u8 *s1, const u8 *s2)
{
memcheck(s1, tal_count(s1));
Expand Down
15 changes: 11 additions & 4 deletions bitcoin/script.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ u8 *bitcoin_wscript_htlc_offer(const tal_t *ctx,
const struct pubkey *remotehtlckey,
const struct sha256 *payment_hash,
const struct pubkey *revocationkey,
bool option_anchor_outputs);
bool option_anchor_outputs,
bool option_anchors_zero_fee_htlc_tx);
u8 **bitcoin_witness_htlc_timeout_tx(const tal_t *ctx,
const struct bitcoin_signature *localsig,
const struct bitcoin_signature *remotesig,
Expand All @@ -109,7 +110,8 @@ u8 *bitcoin_wscript_htlc_receive(const tal_t *ctx,
const struct pubkey *remotekey,
const struct sha256 *payment_hash,
const struct pubkey *revocationkey,
bool option_anchor_outputs);
bool option_anchor_outputs,
bool option_anchors_zero_fee_htlc_tx);
u8 **bitcoin_witness_htlc_success_tx(const tal_t *ctx,
const struct bitcoin_signature *localsig,
const struct bitcoin_signature *remotesig,
Expand All @@ -122,14 +124,16 @@ u8 *bitcoin_wscript_htlc_offer_ripemd160(const tal_t *ctx,
const struct pubkey *remotehtlckey,
const struct ripemd160 *payment_ripemd,
const struct pubkey *revocationkey,
bool option_anchor_outputs);
bool option_anchor_outputs,
bool option_anchors_zero_fee_htlc_tx);
u8 *bitcoin_wscript_htlc_receive_ripemd(const tal_t *ctx,
const struct abs_locktime *htlc_abstimeout,
const struct pubkey *localkey,
const struct pubkey *remotekey,
const struct ripemd160 *payment_ripemd,
const struct pubkey *revocationkey,
bool option_anchor_outputs);
bool option_anchor_outputs,
bool option_anchors_zero_fee_htlc_tx);

/* BOLT #3 HTLC-success/HTLC-timeout output */
u8 *bitcoin_wscript_htlc_tx(const tal_t *ctx,
Expand Down Expand Up @@ -159,6 +163,9 @@ bool is_known_scripttype(const u8 *script);
/* Is this a to-remote witness script (used for option_anchor_outputs)? */
bool is_to_remote_anchored_witness_script(const u8 *script, size_t script_len);

/* Is this an anchor witness script? */
bool is_anchor_witness_script(const u8 *script, size_t script_len);

/* Are these two scripts equal? */
bool scripteq(const u8 *s1, const u8 *s2);

Expand Down
3 changes: 3 additions & 0 deletions bitcoin/test/run-bitcoin_block_from_hex.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
/* Generated stub for fromwire_u8_array */
void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED)
{ fprintf(stderr, "fromwire_u8_array called!\n"); abort(); }
/* Generated stub for is_anchor_witness_script */
bool is_anchor_witness_script(const u8 *script UNNEEDED, size_t script_len UNNEEDED)
{ fprintf(stderr, "is_anchor_witness_script called!\n"); abort(); }
/* Generated stub for is_to_remote_anchored_witness_script */
bool is_to_remote_anchored_witness_script(const u8 *script UNNEEDED, size_t script_len UNNEEDED)
{ fprintf(stderr, "is_to_remote_anchored_witness_script called!\n"); abort(); }
Expand Down
3 changes: 3 additions & 0 deletions bitcoin/test/run-psbt-from-tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED)
void fromwire_sha256_double(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
struct sha256_double *sha256d UNNEEDED)
{ fprintf(stderr, "fromwire_sha256_double called!\n"); abort(); }
/* Generated stub for is_anchor_witness_script */
bool is_anchor_witness_script(const u8 *script UNNEEDED, size_t script_len UNNEEDED)
{ fprintf(stderr, "is_anchor_witness_script called!\n"); abort(); }
/* Generated stub for is_to_remote_anchored_witness_script */
bool is_to_remote_anchored_witness_script(const u8 *script UNNEEDED, size_t script_len UNNEEDED)
{ fprintf(stderr, "is_to_remote_anchored_witness_script called!\n"); abort(); }
Expand Down
3 changes: 3 additions & 0 deletions bitcoin/test/run-tx-encode.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
/* Generated stub for fromwire_u8_array */
void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED)
{ fprintf(stderr, "fromwire_u8_array called!\n"); abort(); }
/* Generated stub for is_anchor_witness_script */
bool is_anchor_witness_script(const u8 *script UNNEEDED, size_t script_len UNNEEDED)
{ fprintf(stderr, "is_anchor_witness_script called!\n"); abort(); }
/* Generated stub for is_to_remote_anchored_witness_script */
bool is_to_remote_anchored_witness_script(const u8 *script UNNEEDED, size_t script_len UNNEEDED)
{ fprintf(stderr, "is_to_remote_anchored_witness_script called!\n"); abort(); }
Expand Down
16 changes: 11 additions & 5 deletions channeld/channeld.c
Original file line number Diff line number Diff line change
Expand Up @@ -1074,9 +1074,11 @@ static struct bitcoin_signature *calc_commitsigs(const tal_t *ctx,
wscript = bitcoin_tx_output_get_witscript(tmpctx, txs[0],
txs[i+1]->wtx->inputs[0].index);
msg = towire_hsmd_sign_remote_htlc_tx(NULL, txs[i + 1], wscript,
&peer->remote_per_commit,
&peer->remote_per_commit,
channel_has(peer->channel,
OPT_ANCHOR_OUTPUTS));
OPT_ANCHOR_OUTPUTS)
|| channel_has(peer->channel,
OPT_ANCHORS_ZERO_FEE_HTLC_TX));

msg = hsm_req(tmpctx, take(msg));
if (!fromwire_hsmd_sign_tx_reply(msg, &htlc_sigs[i]))
Expand Down Expand Up @@ -1605,7 +1607,8 @@ static void handle_peer_commit_sig(struct peer *peer, const u8 *msg)
/* SIGHASH_ALL is implied. */
commit_sig.sighash_type = SIGHASH_ALL;
htlc_sigs = unraw_sigs(tmpctx, raw_sigs,
channel_has(peer->channel, OPT_ANCHOR_OUTPUTS));
channel_has(peer->channel, OPT_ANCHOR_OUTPUTS)
|| channel_has(peer->channel, OPT_ANCHORS_ZERO_FEE_HTLC_TX));

txs =
channel_txs(tmpctx, &htlc_map, NULL,
Expand Down Expand Up @@ -3848,9 +3851,12 @@ static void init_channel(struct peer *peer)
peer->dev_fast_gossip = dev_fast_gossip;
#endif

status_debug("option_static_remotekey = %u, option_anchor_outputs = %u",
status_debug("option_static_remotekey = %u,"
" option_anchor_outputs = %u"
" option_anchors_zero_fee_htlc_tx = %u",
channel_type_has(channel_type, OPT_STATIC_REMOTEKEY),
channel_type_has(channel_type, OPT_ANCHOR_OUTPUTS));
channel_type_has(channel_type, OPT_ANCHOR_OUTPUTS),
channel_type_has(channel_type, OPT_ANCHORS_ZERO_FEE_HTLC_TX));

/* Keeping an array of pointers is better since it allows us to avoid
* extra allocations later. */
Expand Down
Loading