Skip to content

Commit

Permalink
channeld: handle upgrade match.
Browse files Browse the repository at this point in the history
We don't actually set desired_type yet, but this handles it.

Changelog-EXPERIMENTAL: Protocol: we can now upgrade old channels to `option_static_remotekey` from lightning/bolts#868
Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell committed Jun 3, 2021
1 parent b4568ba commit 60b5433
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 3 deletions.
113 changes: 112 additions & 1 deletion channeld/channeld.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}

Expand Down
4 changes: 4 additions & 0 deletions channeld/channeld_wire.csv
Original file line number Diff line number Diff line change
Expand Up @@ -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,
26 changes: 25 additions & 1 deletion channeld/channeld_wiregen.c

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion channeld/channeld_wiregen.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions common/features.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
4 changes: 4 additions & 0 deletions common/features.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
30 changes: 30 additions & 0 deletions lightningd/channel_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand Down

0 comments on commit 60b5433

Please sign in to comment.