From a5fedc4e1fe34dfd3007bc8b746441dfb79ce971 Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 3 Mar 2021 14:07:32 -0600 Subject: [PATCH] df-spec: use an empty bit-set as the basepoint for chan-id at start > If the peer's revocation basepoint is unknown (e.g. `open_channel2`), > a temporary `channel_id` should be found by using a zeroed out basepoint > for the unknown peer. --- common/channel_id.c | 18 ++++++++++ common/channel_id.h | 10 +++++- openingd/dualopend.c | 78 ++++++++++++++++++++++++++------------------ 3 files changed, 74 insertions(+), 32 deletions(-) diff --git a/common/channel_id.c b/common/channel_id.c index 7b1bae721..504cb3033 100644 --- a/common/channel_id.c +++ b/common/channel_id.c @@ -47,6 +47,24 @@ void derive_channel_id_v2(struct channel_id *channel_id, memcpy(channel_id, &sha, sizeof(*channel_id)); } +void derive_tmp_channel_id(struct channel_id *channel_id, + const struct pubkey *opener_basepoint) +{ + struct sha256 sha; + + /* BOLT-f53ca2301232db780843e894f55d95d512f297f9 #2: + * If the peer's revocation basepoint is unknown + * (e.g. `open_channel2`), a temporary `channel_id` should be + * found by using a zeroed out basepoint for the unknown peer. + */ + u8 der_keys[PUBKEY_CMPR_LEN * 2]; + memset(der_keys, 0, PUBKEY_CMPR_LEN); + pubkey_to_der(der_keys + PUBKEY_CMPR_LEN, opener_basepoint); + sha256(&sha, der_keys, sizeof(der_keys)); + BUILD_ASSERT(sizeof(*channel_id) == sizeof(sha)); + memcpy(channel_id, &sha, sizeof(*channel_id)); +} + /* BOLT #2: * * The sending node: diff --git a/common/channel_id.h b/common/channel_id.h index 78e1109bd..9a3aa13e0 100644 --- a/common/channel_id.h +++ b/common/channel_id.h @@ -20,14 +20,22 @@ struct channel_id { /* Define channel_id_eq (no padding) */ STRUCTEQ_DEF(channel_id, 0, id); +/* For v1 channel establishment */ void derive_channel_id(struct channel_id *channel_id, const struct bitcoin_txid *txid, u16 txout); +/* For v1 channel establishment */ +void temporary_channel_id(struct channel_id *channel_id); + +/* For v2 channel establishment */ void derive_channel_id_v2(struct channel_id *channel_id, const struct pubkey *basepoint_1, const struct pubkey *basepoint_2); -void temporary_channel_id(struct channel_id *channel_id); +/* For v2 channel establishment */ +void derive_tmp_channel_id(struct channel_id *channel_id, + const struct pubkey *opener_basepoint); + /* Marshalling/unmarshalling functions */ void towire_channel_id(u8 **pptr, const struct channel_id *channel_id); void fromwire_channel_id(const u8 **cursor, size_t *max, diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 2f3f0d282..861125d13 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -434,6 +434,13 @@ static void check_channel_id(struct state *state, id_in)); } +static bool is_dust(struct tx_state *tx_state, + struct amount_sat amount) +{ + return !amount_sat_greater(amount, tx_state->localconf.dust_limit) + || !amount_sat_greater(amount, tx_state->remoteconf.dust_limit); +} + static void set_reserve(struct tx_state *tx_state, struct amount_sat funding_total, enum tx_role our_role) @@ -542,7 +549,8 @@ static char *check_balances(const tal_t *ctx, * - segwit marker + flag * - input count * - output count - * - locktime */ + * - locktime + */ size_t initiator_weight = bitcoin_tx_core_weight(psbt->num_inputs, psbt->num_outputs); @@ -596,12 +604,8 @@ static char *check_balances(const tal_t *ctx, * - the value of the funding output is * less than the `dust_limit` */ - if (!amount_sat_greater(output_val, - tx_state->remoteconf.dust_limit) || - !amount_sat_greater(output_val, - tx_state->localconf.dust_limit)) { + if (is_dust(tx_state, output_val)) return "funding output is dust"; - } } else { /* BOLT-f53ca2301232db780843e894f55d95d512f297f9 #2: * @@ -667,12 +671,8 @@ static char *check_balances(const tal_t *ctx, * - the `sats` amount is less than or equal to * the `dust_limit` */ - if (!amount_sat_greater(amt, - tx_state->remoteconf.dust_limit) || - !amount_sat_greater(amt, - tx_state->localconf.dust_limit)) { + if (is_dust(tx_state, amt)) return "output is dust"; - } if (is_openers(&psbt->outputs[i].unknowns)) { /* Don't add the funding output to @@ -704,9 +704,9 @@ static char *check_balances(const tal_t *ctx, * ... * - the peer's total input satoshis is less than their outputs */ - if (!amount_sat_greater_eq(tot_input_amt, tot_output_amt)) { - return "inputs less than total outputs"; - } + /* We check both, why not? */ + if (!amount_sat_greater_eq(initiator_inputs, initiator_outs)) + return "initiator inputs less than outputs"; /* BOLT-f53ca2301232db780843e894f55d95d512f297f9 #2: * The receiving node: ... @@ -1424,6 +1424,7 @@ static bool run_tx_interactive(struct state *state, * to a currently added input (or output) */ input_index = psbt_find_serial_input(psbt, serial_id); + /* We choose to error/fail negotiation */ if (input_index == -1) open_err_warn(state, "No input added with serial_id" @@ -1853,7 +1854,7 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) struct bitcoin_blkid chain_hash; struct tlv_opening_tlvs *open_tlv; char *err_reason; - struct channel_id cid; + struct channel_id tmp_chan_id; u8 *msg; struct amount_sat total; enum dualopend_wire msg_type; @@ -1863,7 +1864,7 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) open_tlv = tlv_opening_tlvs_new(tmpctx); if (!fromwire_open_channel2(oc2_msg, &chain_hash, - &state->channel_id, + &state->channel_id, /* Temporary! */ &state->feerate_per_kw_funding, &state->feerate_per_kw_commitment, &tx_state->opener_funding, @@ -1890,6 +1891,27 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) } else state->upfront_shutdown_script[REMOTE] = NULL; + /* BOLT-* #2 + * If the peer's revocation basepoint is unknown (e.g. + * `open_channel2`), a temporary `channel_id` should be found + * by using a zeroed out basepoint for the unknown peer. + */ + derive_tmp_channel_id(&tmp_chan_id, + &state->their_points.revocation); + if (!channel_id_eq(&state->channel_id, &tmp_chan_id)) + negotiation_failed(state, "open_channel2 channel_id incorrect." + " Expected %s, received %s", + type_to_string(tmpctx, struct channel_id, + &tmp_chan_id), + type_to_string(tmpctx, struct channel_id, + &state->channel_id)); + + /* Everything's ok. Let's figure out the actual channel_id now */ + derive_channel_id_v2(&state->channel_id, + &state->our_points.revocation, + &state->their_points.revocation); + + /* Save feerate on the tx_state as well */ tx_state->feerate_per_kw_funding = state->feerate_per_kw_funding; @@ -1925,13 +1947,8 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) return; } - /* We can figure out the channel id now */ - derive_channel_id_v2(&cid, - &state->our_points.revocation, - &state->their_points.revocation); - msg = towire_dualopend_got_offer(NULL, - &cid, + &state->channel_id, tx_state->opener_funding, tx_state->remoteconf.dust_limit, tx_state->remoteconf.max_htlc_value_in_flight, @@ -1965,9 +1982,6 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) * the original feerate we'll base any increases off of. */ state->feerate_per_kw_funding = tx_state->feerate_per_kw_funding; - /* Set the channel id now */ - state->channel_id = cid; - if (!tx_state->psbt) tx_state->psbt = create_psbt(tx_state, 0, 0, tx_state->tx_locktime); @@ -2353,11 +2367,13 @@ static void opener_start(struct state *state, u8 *msg) tx_state->feerate_per_kw_funding = state->feerate_per_kw_funding; open_tlv = tlv_opening_tlvs_new(tmpctx); - /* Set the channel_id to a temporary id, we'll update - * this as soon as we hear back from accept, but if they - * send us an error in the meantime, we need to be able to - * understand it */ - temporary_channel_id(&state->channel_id); + /* BOLT-* #2 + * If the peer's revocation basepoint is unknown (e.g. + * `open_channel2`), a temporary `channel_id` should be found + * by using a zeroed out basepoint for the unknown peer. + */ + derive_tmp_channel_id(&state->channel_id, + &state->our_points.revocation); if (!state->upfront_shutdown_script[LOCAL]) state->upfront_shutdown_script[LOCAL] @@ -2432,7 +2448,7 @@ static void opener_start(struct state *state, u8 *msg) } else state->upfront_shutdown_script[REMOTE] = NULL; - /* Now we can set the 'real channel id' */ + /* Now we know the 'real channel id' */ derive_channel_id_v2(&state->channel_id, &state->our_points.revocation, &state->their_points.revocation);