hsmd: Implement hsmd_forget_channel for Channel Deletion in HSMD

Changelog-Added: hsmd: Added hsmd_forget_channel to enable explicit channel deletion. ([#6987])

Motivation: Previously, a signer prematurely forgetting a channel led
to failures in unresolved channel requests. This update introduces
hsmd_forget_channel, allowing nodes to explicitly notify signers when
a channel is irrevocably resolved and can be safely forgotten. This
ensures synchronized channel cleanup between nodes and signers.

This change maintains backward and forward compatibility. Nodes
explicitly check whether a signer has `WIRE_HSMD_FORGET_CHANNEL`
capability before sending the message.  Nodes without
`WIRE_HSMD_FORGET_CHANNEL` capability won't send this message. Signers
capable of handling this message but not receiving it will continue to
use conservative pruning methods.

Fixes #6987
This commit is contained in:
Ken Sedgwick 2023-12-03 19:39:45 -08:00 committed by Christian Decker
parent 78deb485fb
commit e9ff50df96
6 changed files with 50 additions and 0 deletions

View file

@ -19,6 +19,7 @@
* v4 with capabilities called permissions: 7c5bf8ec7cf30302740db85260a9d1ac2c5b0323a2376c28df6b611831f91655
* v4 with renaming of channel_ready to setup_channel: 60b92a0930b631cc77df564cb9235e6cb220f4337a2bb00e5153145e0bf8c80e
* v4 with buried outpoint check: f44fae666895cab0347b3de7c245267c71cc7de834827b83e286e86318c08aec
* v4 with forget_channel: d87c6934ea188f92785d38d7cd0b13ed7f76aa7417f3200baf0c7b5aa832fe29
*/
#define HSM_MIN_VERSION 3
#define HSM_MAX_VERSION 4

View file

@ -647,6 +647,7 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c)
case WIRE_HSMD_SETUP_CHANNEL:
case WIRE_HSMD_CHECK_OUTPOINT:
case WIRE_HSMD_LOCK_OUTPOINT:
case WIRE_HSMD_FORGET_CHANNEL:
case WIRE_HSMD_SIGN_COMMITMENT_TX:
case WIRE_HSMD_VALIDATE_COMMITMENT_TX:
case WIRE_HSMD_VALIDATE_REVOCATION:
@ -694,6 +695,7 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c)
case WIRE_HSMD_SETUP_CHANNEL_REPLY:
case WIRE_HSMD_CHECK_OUTPOINT_REPLY:
case WIRE_HSMD_LOCK_OUTPOINT_REPLY:
case WIRE_HSMD_FORGET_CHANNEL_REPLY:
case WIRE_HSMD_NODE_ANNOUNCEMENT_SIG_REPLY:
case WIRE_HSMD_SIGN_WITHDRAWAL_REPLY:
case WIRE_HSMD_SIGN_INVOICE_REPLY:

View file

@ -105,6 +105,14 @@ msgdata,hsmd_lock_outpoint,funding_txout,u16,
# No value returned.
msgtype,hsmd_lock_outpoint_reply,137
# Forget channel.
msgtype,hsmd_forget_channel,34
msgdata,hsmd_forget_channel,id,node_id,
msgdata,hsmd_forget_channel,dbid,u64,
# No value returned.
msgtype,hsmd_forget_channel_reply,134
# Return signature for a funding tx.
#include <common/utxo.h>

1 # Clients should not give a bad request but not the HSM's decision to crash.
105 msgdata,hsmd_sign_withdrawal,psbt,wally_psbt, msgdata,hsmd_node_announcement_sig_reply,signature,secp256k1_ecdsa_signature,
106 msgtype,hsmd_sign_withdrawal_reply,107 # Sign a withdrawal request
107 msgdata,hsmd_sign_withdrawal_reply,psbt,wally_psbt, #include <bitcoin/psbt.h>
108 msgtype,hsmd_sign_withdrawal,7
109 msgdata,hsmd_sign_withdrawal,num_inputs,u16,
110 msgdata,hsmd_sign_withdrawal,inputs,utxo,num_inputs
111 msgdata,hsmd_sign_withdrawal,psbt,wally_psbt,
112 msgtype,hsmd_sign_withdrawal_reply,107
113 msgdata,hsmd_sign_withdrawal_reply,psbt,wally_psbt,
114 # Sign an invoice
115 msgtype,hsmd_sign_invoice,8
116 # Sign an invoice msgdata,hsmd_sign_invoice,len,u16,
117 msgtype,hsmd_sign_invoice,8 msgdata,hsmd_sign_invoice,u5bytes,u8,len
118 msgdata,hsmd_sign_invoice,len,u16, msgdata,hsmd_sign_invoice,hrplen,u16,

View file

@ -118,6 +118,7 @@ bool hsmd_check_client_capabilities(struct hsmd_client *client,
case WIRE_HSMD_INIT:
case WIRE_HSMD_NEW_CHANNEL:
case WIRE_HSMD_FORGET_CHANNEL:
case WIRE_HSMD_CLIENT_HSMFD:
case WIRE_HSMD_SIGN_WITHDRAWAL:
case WIRE_HSMD_SIGN_INVOICE:
@ -150,6 +151,7 @@ bool hsmd_check_client_capabilities(struct hsmd_client *client,
case WIRE_HSMD_SETUP_CHANNEL_REPLY:
case WIRE_HSMD_CHECK_OUTPOINT_REPLY:
case WIRE_HSMD_LOCK_OUTPOINT_REPLY:
case WIRE_HSMD_FORGET_CHANNEL_REPLY:
case WIRE_HSMD_NODE_ANNOUNCEMENT_SIG_REPLY:
case WIRE_HSMD_SIGN_WITHDRAWAL_REPLY:
case WIRE_HSMD_SIGN_INVOICE_REPLY:
@ -382,6 +384,21 @@ static u8 *handle_setup_channel(struct hsmd_client *c, const u8 *msg_in)
return towire_hsmd_setup_channel_reply(NULL);
}
/* ~This stub implementation is overriden by fully validating signers
* that need to manage per-channel state. */
static u8 *handle_forget_channel(struct hsmd_client *c, const u8 *msg_in)
{
struct node_id peer_id;
u64 dbid;
if (!fromwire_hsmd_forget_channel(msg_in, &peer_id, &dbid))
return hsmd_status_malformed_request(c, msg_in);
/* Stub implementation */
return towire_hsmd_forget_channel_reply(NULL);
}
/* ~This stub implementation is overriden by fully validating signers
* to ensure they are caught up when outpoints are freshly buried */
static u8 *handle_check_outpoint(struct hsmd_client *c, const u8 *msg_in)
@ -1945,6 +1962,8 @@ u8 *hsmd_handle_client_message(const tal_t *ctx, struct hsmd_client *client,
return handle_check_outpoint(client, msg);
case WIRE_HSMD_LOCK_OUTPOINT:
return handle_lock_outpoint(client, msg);
case WIRE_HSMD_FORGET_CHANNEL:
return handle_forget_channel(client, msg);
case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY:
return handle_get_output_scriptpubkey(client, msg);
case WIRE_HSMD_CHECK_FUTURE_SECRET:
@ -2024,6 +2043,7 @@ u8 *hsmd_handle_client_message(const tal_t *ctx, struct hsmd_client *client,
case WIRE_HSMD_SETUP_CHANNEL_REPLY:
case WIRE_HSMD_CHECK_OUTPOINT_REPLY:
case WIRE_HSMD_LOCK_OUTPOINT_REPLY:
case WIRE_HSMD_FORGET_CHANNEL_REPLY:
case WIRE_HSMD_NODE_ANNOUNCEMENT_SIG_REPLY:
case WIRE_HSMD_SIGN_WITHDRAWAL_REPLY:
case WIRE_HSMD_SIGN_INVOICE_REPLY:
@ -2067,6 +2087,7 @@ u8 *hsmd_init(struct secret hsm_secret,
WIRE_HSMD_SIGN_HTLC_TX_MINGLE,
WIRE_HSMD_SIGN_SPLICE_TX,
WIRE_HSMD_CHECK_OUTPOINT,
WIRE_HSMD_FORGET_CHANNEL,
};
/*~ Don't swap this. */

View file

@ -89,9 +89,21 @@ static void destroy_channel(struct channel *channel)
void delete_channel(struct channel *channel STEALS)
{
const u8 *msg;
struct peer *peer = channel->peer;
if (channel->dbid != 0)
wallet_channel_close(channel->peer->ld->wallet, channel->dbid);
/* Tell the hsm to forget the channel, needs to be after it's
* been forgotten here */
if (hsm_capable(channel->peer->ld, WIRE_HSMD_FORGET_CHANNEL)) {
msg = towire_hsmd_forget_channel(NULL, &channel->peer->id, channel->dbid);
msg = hsm_sync_req(tmpctx, channel->peer->ld, take(msg));
if (!fromwire_hsmd_forget_channel_reply(msg))
fatal("HSM gave bad hsm_forget_channel_reply %s", tal_hex(msg, msg));
}
tal_free(channel);
maybe_delete_peer(peer);

View file

@ -272,6 +272,9 @@ bool fromwire_hsmd_init_reply_v4(const tal_t *ctx UNNEEDED, const void *p UNNEED
/* Generated stub for fromwire_hsmd_new_channel_reply */
bool fromwire_hsmd_new_channel_reply(const void *p UNNEEDED)
{ fprintf(stderr, "fromwire_hsmd_new_channel_reply called!\n"); abort(); }
/* Generated stub for fromwire_hsmd_forget_channel_reply */
bool fromwire_hsmd_forget_channel_reply(const void *p UNNEEDED)
{ fprintf(stderr, "fromwire_hsmd_forget_channel_reply called!\n"); abort(); }
/* Generated stub for fromwire_hsmd_sign_commitment_tx_reply */
bool fromwire_hsmd_sign_commitment_tx_reply(const void *p UNNEEDED, struct bitcoin_signature *sig UNNEEDED)
{ fprintf(stderr, "fromwire_hsmd_sign_commitment_tx_reply called!\n"); abort(); }
@ -1008,6 +1011,9 @@ u8 *towire_hsmd_init(const tal_t *ctx UNNEEDED, const struct bip32_key_version *
/* Generated stub for towire_hsmd_new_channel */
u8 *towire_hsmd_new_channel(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, u64 dbid UNNEEDED)
{ fprintf(stderr, "towire_hsmd_new_channel called!\n"); abort(); }
/* Generated stub for towire_hsmd_forget_channel */
u8 *towire_hsmd_forget_channel(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, u64 dbid UNNEEDED)
{ fprintf(stderr, "towire_hsmd_forget_channel called!\n"); abort(); }
/* Generated stub for towire_hsmd_sign_commitment_tx */
u8 *towire_hsmd_sign_commitment_tx(const tal_t *ctx UNNEEDED, const struct node_id *peer_id UNNEEDED, u64 channel_dbid UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, const struct pubkey *remote_funding_key UNNEEDED, u64 commit_num UNNEEDED)
{ fprintf(stderr, "towire_hsmd_sign_commitment_tx called!\n"); abort(); }