mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-15 11:59:16 +01:00
hsmd: implement the hsmd outpoint check
Tihis commit is implementing a 2-phase commit between the signer the node and the peer. The main reason for this is that everybody must agree on the lock, otherwise one of them will want N signatures (on the splice candidates), and another will produce only 1 signature. check_outpoint is the "prepare" for the signer, and lock_outpoint is the "commit". if check_outpoint returns true, lock_outpoint must not fail. Link: https://github.com/ElementsProject/lightning/issues/6722 Suggested-by: @devrandom Co-Developed-by: Ken Sedgwick <ken@bonsai.com> Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
This commit is contained in:
parent
485cabb25e
commit
44798e298c
4 changed files with 99 additions and 3 deletions
|
@ -663,6 +663,48 @@ static bool channel_announcement_negotiate(struct peer *peer)
|
|||
return sent_announcement;
|
||||
}
|
||||
|
||||
static void lock_signer_outpoint(const struct bitcoin_outpoint *outpoint)
|
||||
{
|
||||
const u8 *msg;
|
||||
bool is_buried = false;
|
||||
|
||||
/* FIXME(vincenzopalazzo): Sleeping in a deamon of cln should be never fine
|
||||
* howerver the core deamon of cln will never trigger the sleep.
|
||||
*
|
||||
* I think that the correct solution for this is a timer base solution, but this
|
||||
* required a little bit of refactoring */
|
||||
do {
|
||||
/* Make sure the hsmd agrees that this outpoint is
|
||||
* sufficiently buried. */
|
||||
msg = towire_hsmd_check_outpoint(NULL, &outpoint->txid, outpoint->n);
|
||||
msg = hsm_req(tmpctx, take(msg));
|
||||
if (!fromwire_hsmd_check_outpoint_reply(msg, &is_buried))
|
||||
status_failed(STATUS_FAIL_HSM_IO,
|
||||
"Bad hsmd_check_outpoint_reply: %s",
|
||||
tal_hex(tmpctx, msg));
|
||||
|
||||
/* the signer should have a shorter buried height requirement so
|
||||
* it almost always will be ready ahead of us.*/
|
||||
if (!is_buried)
|
||||
sleep(10);
|
||||
} while (!is_buried);
|
||||
|
||||
/* tell the signer that we are now locked */
|
||||
msg = towire_hsmd_lock_outpoint(NULL, &outpoint->txid, outpoint->n);
|
||||
msg = hsm_req(tmpctx, take(msg));
|
||||
if (!fromwire_hsmd_lock_outpoint_reply(msg))
|
||||
status_failed(STATUS_FAIL_HSM_IO,
|
||||
"Bad hsmd_lock_outpoint_reply: %s",
|
||||
tal_hex(tmpctx, msg));
|
||||
}
|
||||
|
||||
/* Call this method when channel_ready status are changed. */
|
||||
static void check_mutual_channel_ready(const struct peer *peer)
|
||||
{
|
||||
if (peer->channel_ready[LOCAL] && peer->channel_ready[REMOTE])
|
||||
lock_signer_outpoint(&peer->channel->funding);
|
||||
}
|
||||
|
||||
/* Call this method when splice_locked status are changed. If both sides have
|
||||
* splice_locked'ed than this function consumes the `splice_locked_ready` values
|
||||
* and considers the channel funding to be switched to the splice tx. */
|
||||
|
@ -733,6 +775,9 @@ static void check_mutual_splice_locked(struct peer *peer)
|
|||
status_debug("mutual splice_locked, channel updated to: %s",
|
||||
type_to_string(tmpctx, struct channel, peer->channel));
|
||||
|
||||
/* ensure the signer is locking at the same time */
|
||||
lock_signer_outpoint(&inflight->outpoint);
|
||||
|
||||
msg = towire_channeld_got_splice_locked(NULL, inflight->amnt,
|
||||
inflight->splice_amnt,
|
||||
&inflight->outpoint.txid);
|
||||
|
@ -808,6 +853,7 @@ static void handle_peer_channel_ready(struct peer *peer, const u8 *msg)
|
|||
|
||||
peer->tx_sigs_allowed = false;
|
||||
peer->channel_ready[REMOTE] = true;
|
||||
check_mutual_channel_ready(peer);
|
||||
if (tlvs->short_channel_id != NULL) {
|
||||
status_debug(
|
||||
"Peer told us that they'll use alias=%s for this channel",
|
||||
|
|
|
@ -1359,7 +1359,8 @@ bool peer_start_channeld(struct channel *channel,
|
|||
| HSM_PERM_SIGN_REMOTE_TX
|
||||
| HSM_PERM_SIGN_ONCHAIN_TX
|
||||
| HSM_PERM_SIGN_CLOSING_TX
|
||||
| HSM_PERM_SIGN_SPLICE_TX);
|
||||
| HSM_PERM_SIGN_SPLICE_TX
|
||||
| HSM_PERM_LOCK_OUTPOINT);
|
||||
|
||||
channel_set_owner(channel,
|
||||
new_channel_subd(channel, ld,
|
||||
|
|
|
@ -3809,7 +3809,8 @@ bool peer_start_dualopend(struct peer *peer,
|
|||
hsmfd = hsm_get_client_fd(peer->ld, &peer->id, channel->unsaved_dbid,
|
||||
HSM_PERM_COMMITMENT_POINT
|
||||
| HSM_PERM_SIGN_REMOTE_TX
|
||||
| HSM_PERM_SIGN_WILL_FUND_OFFER);
|
||||
| HSM_PERM_SIGN_WILL_FUND_OFFER
|
||||
| HSM_PERM_LOCK_OUTPOINT);
|
||||
|
||||
channel->owner = new_channel_subd(channel,
|
||||
peer->ld,
|
||||
|
@ -3881,7 +3882,8 @@ bool peer_restart_dualopend(struct peer *peer,
|
|||
hsmfd = hsm_get_client_fd(peer->ld, &peer->id, channel->dbid,
|
||||
HSM_PERM_COMMITMENT_POINT
|
||||
| HSM_PERM_SIGN_REMOTE_TX
|
||||
| HSM_PERM_SIGN_WILL_FUND_OFFER);
|
||||
| HSM_PERM_SIGN_WILL_FUND_OFFER
|
||||
| HSM_PERM_LOCK_OUTPOINT);
|
||||
|
||||
channel_set_owner(channel,
|
||||
new_channel_subd(channel, peer->ld,
|
||||
|
|
|
@ -426,6 +426,51 @@ static void billboard_update(struct state *state)
|
|||
peer_billboard(false, update);
|
||||
}
|
||||
|
||||
static void lock_signer_outpoint(const struct bitcoin_outpoint *outpoint)
|
||||
{
|
||||
const u8 *msg;
|
||||
bool is_buried = false;
|
||||
|
||||
|
||||
/* FIXME(vincenzopalazzo): Sleeping in a deamon of cln should be never fine
|
||||
* howerver the core deamon of cln will never trigger the sleep.
|
||||
*
|
||||
* I think that the correct solution for this is a timer base solution, but this
|
||||
* required to implement all the timers in the deamon. */
|
||||
do {
|
||||
/* Make sure the hsmd agrees that this outpoint is
|
||||
* sufficiently buried. */
|
||||
msg = towire_hsmd_check_outpoint(NULL, &outpoint->txid, outpoint->n);
|
||||
wire_sync_write(HSM_FD, take(msg));
|
||||
msg = wire_sync_read(tmpctx, HSM_FD);
|
||||
if (!fromwire_hsmd_check_outpoint_reply(msg, &is_buried))
|
||||
status_failed(STATUS_FAIL_HSM_IO,
|
||||
"Bad hsmd_check_outpoint_reply: %s",
|
||||
tal_hex(tmpctx, msg));
|
||||
|
||||
/* the signer should have a shorter buried height requirement so
|
||||
* it almost always will be ready ahead of us.*/
|
||||
if (!is_buried)
|
||||
sleep(10);
|
||||
} while (!is_buried);
|
||||
|
||||
/* tell the signer that we are now locked */
|
||||
msg = towire_hsmd_lock_outpoint(NULL, &outpoint->txid, outpoint->n);
|
||||
wire_sync_write(HSM_FD, take(msg));
|
||||
msg = wire_sync_read(tmpctx, HSM_FD);
|
||||
if (!fromwire_hsmd_lock_outpoint_reply(msg))
|
||||
status_failed(STATUS_FAIL_HSM_IO,
|
||||
"Bad hsmd_lock_outpoint_reply: %s",
|
||||
tal_hex(tmpctx, msg));
|
||||
}
|
||||
|
||||
/* Call this method when channel_ready status are changed. */
|
||||
static void check_mutual_channel_ready(const struct state *state)
|
||||
{
|
||||
if (state->channel_ready[LOCAL] && state->channel_ready[REMOTE])
|
||||
lock_signer_outpoint(&state->channel->funding);
|
||||
}
|
||||
|
||||
static void send_shutdown(struct state *state, const u8 *final_scriptpubkey)
|
||||
{
|
||||
u8 *msg;
|
||||
|
@ -1265,6 +1310,7 @@ static u8 *handle_channel_ready(struct state *state, u8 *msg)
|
|||
}
|
||||
|
||||
state->channel_ready[REMOTE] = true;
|
||||
check_mutual_channel_ready(state);
|
||||
billboard_update(state);
|
||||
|
||||
if (state->channel_ready[LOCAL])
|
||||
|
@ -3789,6 +3835,7 @@ static void send_channel_ready(struct state *state)
|
|||
peer_write(state->pps, take(msg));
|
||||
|
||||
state->channel_ready[LOCAL] = true;
|
||||
check_mutual_channel_ready(state);
|
||||
billboard_update(state);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue