diff --git a/channeld/channeld.c b/channeld/channeld.c index f3ba9e201893..6b6494c1d2f7 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -368,6 +368,50 @@ static bool handle_master_request_later(struct peer *peer, const u8 *msg) } return false; } + +static bool channel_type_eq(const struct channel_type *a, + const struct channel_type *b) +{ + return featurebits_eq(a->features, b->features); +} + +static bool match_type(const struct channel_type *desired, + const struct channel_type *current, + struct channel_type **upgradable) +{ + /* Missing fields are possible. */ + if (!desired || !current) + return false; + + if (channel_type_eq(desired, current)) + return true; + + for (size_t i = 0; i < tal_count(upgradable); i++) { + if (channel_type_eq(desired, upgradable[i])) + return true; + } + + return false; +} + +static void set_channel_type(struct channel *channel, + const struct channel_type *type) +{ + const struct channel_type *cur = channel_type(tmpctx, channel); + + if (channel_type_eq(cur, type)) + return; + + /* We only allow one upgrade at the moment, so that's it. */ + assert(!channel->option_static_remotekey); + assert(feature_offered(type->features, OPT_STATIC_REMOTEKEY)); + + /* Do upgrade, tell master. */ + channel->option_static_remotekey = true; + status_unusual("Upgraded channel to [%s]", + fmt_featurebits(tmpctx, type->features)); + wire_sync_write(MASTER_FD, take(towire_channeld_upgraded(NULL, true))); +} #else /* !EXPERIMENTAL_FEATURES */ static bool handle_master_request_later(struct peer *peer, const u8 *msg) { @@ -2499,7 +2543,8 @@ static void peer_reconnect(struct peer *peer, &my_current_per_commitment_point, NULL); #if EXPERIMENTAL_FEATURES - send_tlvs = tlv_channel_reestablish_tlvs_new(tmpctx); + /* Subtle: we free tmpctx below as we loop, so tal off peer */ + send_tlvs = tlv_channel_reestablish_tlvs_new(peer); /* BOLT-upgrade_protocol #2: * A node sending `channel_reestablish`, if it supports upgrading channels: * - MUST set `next_to_send` the commitment number of the next @@ -2797,6 +2842,71 @@ static void peer_reconnect(struct peer *peer, fmt_featurebits(tmpctx, recv_tlvs->upgradable[i]->features)); } + + /* BOLT-upgrade_protocol #2: + * + * A node receiving `channel_reestablish`: + * - if it has to retransmit `commitment_signed` or `revoke_and_ack`: + * - MUST consider the channel feature change failed. + */ + if (retransmit_commitment_signed || retransmit_revoke_and_ack) { + status_debug("No upgrade: we retransmitted"); + /* BOLT-upgrade_protocol #2: + * + * - if `next_to_send` is missing, or not equal to the + * `next_commitment_number` it sent: + * - MUST consider the channel feature change failed. + */ + } else if (!recv_tlvs->next_to_send) { + status_debug("No upgrade: no next_to_send received"); + } else if (*recv_tlvs->next_to_send != peer->next_index[LOCAL]) { + status_debug("No upgrade: they're retransmitting"); + /* BOLT-upgrade_protocol #2: + * + * - if updates are pending on either sides' commitment transaction: + * - MUST consider the channel feature change failed. + */ + /* Note that we can have HTLCs we *want* to add or remove + * but haven't yet: thats OK! */ + } else if (pending_updates(peer->channel, LOCAL, true) + || pending_updates(peer->channel, REMOTE, true)) { + status_debug("No upgrade: pending changes"); + } else { + const struct tlv_channel_reestablish_tlvs *initr, *ninitr; + const struct channel_type *type; + + if (peer->channel->opener == LOCAL) { + initr = send_tlvs; + ninitr = recv_tlvs; + } else { + initr = recv_tlvs; + ninitr = send_tlvs; + } + + /* BOLT-upgrade_protocol #2: + * + * - if `desired_type` matches `current_type` or any + * `upgradable` `upgrades`: + * - MUST consider the channel type to be `desired_type`. + * - otherwise: + * - MUST consider the channel feature change failed. + * - if there is a `current_type` field: + * - MUST consider the channel type to be `current_type`. + */ + /* Note: returns NULL on missing fields, aka NULL */ + if (match_type(initr->desired_type, + ninitr->current_type, ninitr->upgradable)) + type = initr->desired_type; + else if (ninitr->current_type) + type = ninitr->current_type; + else + type = NULL; + + if (type) + set_channel_type(peer->channel, type); + } + tal_free(send_tlvs); + #endif /* EXPERIMENTAL_FEATURES */ /* Corner case: we didn't send shutdown before because update_add_htlc @@ -3246,6 +3356,7 @@ static void req_in(struct peer *peer, const u8 *msg) case WIRE_CHANNELD_DEV_MEMLEAK_REPLY: case WIRE_CHANNELD_SEND_ERROR_REPLY: case WIRE_CHANNELD_DEV_QUIESCE_REPLY: + case WIRE_CHANNELD_UPGRADED: break; } diff --git a/channeld/channeld_wire.csv b/channeld/channeld_wire.csv index a376f5a6536f..8af0756a34a1 100644 --- a/channeld/channeld_wire.csv +++ b/channeld/channeld_wire.csv @@ -221,3 +221,7 @@ msgtype,channeld_send_error_reply,1108 # Ask channeld to quiesce. msgtype,channeld_dev_quiesce,1009 msgtype,channeld_dev_quiesce_reply,1109 + +# Tell master we're upgrading the commitment tx. +msgtype,channeld_upgraded,1011 +msgdata,channeld_upgraded,option_static_remotekey,bool, diff --git a/channeld/channeld_wiregen.c b/channeld/channeld_wiregen.c index ebf2efcae2f2..0a4d375bc327 100644 --- a/channeld/channeld_wiregen.c +++ b/channeld/channeld_wiregen.c @@ -48,6 +48,7 @@ const char *channeld_wire_name(int e) case WIRE_CHANNELD_SEND_ERROR_REPLY: return "WIRE_CHANNELD_SEND_ERROR_REPLY"; case WIRE_CHANNELD_DEV_QUIESCE: return "WIRE_CHANNELD_DEV_QUIESCE"; case WIRE_CHANNELD_DEV_QUIESCE_REPLY: return "WIRE_CHANNELD_DEV_QUIESCE_REPLY"; + case WIRE_CHANNELD_UPGRADED: return "WIRE_CHANNELD_UPGRADED"; } snprintf(invalidbuf, sizeof(invalidbuf), "INVALID %i", e); @@ -85,6 +86,7 @@ bool channeld_wire_is_defined(u16 type) case WIRE_CHANNELD_SEND_ERROR_REPLY:; case WIRE_CHANNELD_DEV_QUIESCE:; case WIRE_CHANNELD_DEV_QUIESCE_REPLY:; + case WIRE_CHANNELD_UPGRADED:; return true; } return false; @@ -1113,4 +1115,26 @@ bool fromwire_channeld_dev_quiesce_reply(const void *p) return false; return cursor != NULL; } -// SHA256STAMP:fa8ee25e2f6082e9889962218e6e345dcb4430840b8f831b40cbb0c415b690b5 + +/* WIRE: CHANNELD_UPGRADED */ +/* Tell master we're upgrading the commitment tx. */ +u8 *towire_channeld_upgraded(const tal_t *ctx, bool option_static_remotekey) +{ + u8 *p = tal_arr(ctx, u8, 0); + + towire_u16(&p, WIRE_CHANNELD_UPGRADED); + towire_bool(&p, option_static_remotekey); + + return memcheck(p, tal_count(p)); +} +bool fromwire_channeld_upgraded(const void *p, bool *option_static_remotekey) +{ + const u8 *cursor = p; + size_t plen = tal_count(p); + + if (fromwire_u16(&cursor, &plen) != WIRE_CHANNELD_UPGRADED) + return false; + *option_static_remotekey = fromwire_bool(&cursor, &plen); + return cursor != NULL; +} +// SHA256STAMP:2d7b763e89512ad8c5921b90c13f37ac83ab0016384c38e8c8e831683d668651 diff --git a/channeld/channeld_wiregen.h b/channeld/channeld_wiregen.h index 1b4293a30853..3dde409668f6 100644 --- a/channeld/channeld_wiregen.h +++ b/channeld/channeld_wiregen.h @@ -73,6 +73,8 @@ enum channeld_wire { /* Ask channeld to quiesce. */ WIRE_CHANNELD_DEV_QUIESCE = 1009, WIRE_CHANNELD_DEV_QUIESCE_REPLY = 1109, + /* Tell master we're upgrading the commitment tx. */ + WIRE_CHANNELD_UPGRADED = 1011, }; const char *channeld_wire_name(int e); @@ -223,6 +225,11 @@ bool fromwire_channeld_dev_quiesce(const void *p); u8 *towire_channeld_dev_quiesce_reply(const tal_t *ctx); bool fromwire_channeld_dev_quiesce_reply(const void *p); +/* WIRE: CHANNELD_UPGRADED */ +/* Tell master we're upgrading the commitment tx. */ +u8 *towire_channeld_upgraded(const tal_t *ctx, bool option_static_remotekey); +bool fromwire_channeld_upgraded(const void *p, bool *option_static_remotekey); + #endif /* LIGHTNING_CHANNELD_CHANNELD_WIREGEN_H */ -// SHA256STAMP:fa8ee25e2f6082e9889962218e6e345dcb4430840b8f831b40cbb0c415b690b5 +// SHA256STAMP:2d7b763e89512ad8c5921b90c13f37ac83ab0016384c38e8c8e831683d668651 diff --git a/common/features.c b/common/features.c index a0e6fe7bc357..d77f514666e3 100644 --- a/common/features.c +++ b/common/features.c @@ -476,6 +476,20 @@ u8 *featurebits_or(const tal_t *ctx, const u8 *f1 TAKES, const u8 *f2 TAKES) return result; } +bool featurebits_eq(const u8 *f1, const u8 *f2) +{ + size_t len = tal_bytelen(f1); + + if (tal_bytelen(f2) > len) + len = tal_bytelen(f2); + + for (size_t i = 0; i < len * 8; i++) { + if (feature_is_set(f1, i) != feature_is_set(f2, i)) + return false; + } + return true; +} + struct feature_set *fromwire_feature_set(const tal_t *ctx, const u8 **cursor, size_t *max) { diff --git a/common/features.h b/common/features.h index 485262acef6d..0de7c31c9571 100644 --- a/common/features.h +++ b/common/features.h @@ -71,6 +71,10 @@ void set_feature_bit(u8 **ptr, u32 bit); /* Given two featurebit vectors, combine them by applying a logical OR. */ u8 *featurebits_or(const tal_t *ctx, const u8 *f1 TAKES, const u8 *f2 TAKES); +/* Are these two feature bitsets functionally equal (one may have + * trailing zeroes)? */ +bool featurebits_eq(const u8 *f1, const u8 *f2); + /* Good for debugging: returns comma-separated string of bits. */ const char *fmt_featurebits(const tal_t *ctx, const u8 *featurebits); diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 51107817b6bf..e8c87401af1d 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -370,6 +370,29 @@ void forget_channel(struct channel *channel, const char *why) forget(channel); } +#if EXPERIMENTAL_FEATURES +static void handle_channel_upgrade(struct channel *channel, + const u8 *msg) +{ + bool option_static_remotekey; + + if (!fromwire_channeld_upgraded(msg, &option_static_remotekey)) { + channel_internal_error(channel, "bad handle_channel_upgrade: %s", + tal_hex(tmpctx, msg)); + return; + } + + channel->static_remotekey_start[LOCAL] = channel->next_index[LOCAL]; + channel->static_remotekey_start[REMOTE] = channel->next_index[REMOTE]; + log_debug(channel->log, + "option_static_remotekey enabled at %"PRIu64"/%"PRIu64, + channel->static_remotekey_start[LOCAL], + channel->static_remotekey_start[REMOTE]); + + wallet_channel_save(channel->peer->ld->wallet, channel); +} +#endif /* EXPERIMENTAL_FEATURES */ + static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) { enum channeld_wire t = fromwire_peektype(msg); @@ -405,6 +428,13 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) case WIRE_CHANNELD_SEND_ERROR_REPLY: handle_error_channel(sd->channel, msg); break; +#if EXPERIMENTAL_FEATURES + case WIRE_CHANNELD_UPGRADED: + handle_channel_upgrade(sd->channel, msg); + break; +#else + case WIRE_CHANNELD_UPGRADED: +#endif /* And we never get these from channeld. */ case WIRE_CHANNELD_INIT: case WIRE_CHANNELD_FUNDING_DEPTH: