Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion contrib/msggen/msggen/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -13029,6 +13029,13 @@
"description": [
"Transaction to use for funding (does not need to be signed but must be otherwise complete)."
]
},
"withhold": {
"type": "boolean",
"added": "v25.12",
"description": [
"Mark this channel 'withheld' so we know we haven't broadcast the funding transaction. If the channel is closed before we call `sendpsbt` on this psbt, it will simply be closed immediately."
]
}
}
},
Expand Down Expand Up @@ -17285,6 +17292,8 @@
"total_htlcs_sent",
"funding_txid",
"funding_outnum",
"funding_psbt",
"funding_withheld",
"leased",
"final_to_us_msat",
"min_to_us_msat",
Expand Down Expand Up @@ -17430,6 +17439,20 @@
"The 0-based output number of the funding transaction which opens the channel."
]
},
"funding_psbt": {
"type": "string",
"added": "v25.12",
"description": [
"The PSBT (may be non-final or unsigned) we should use to open the channel, if any"
]
},
"funding_withheld": {
"type": "boolean",
"added": "v25.12",
"description": [
"True if we have not broadcast the funding transaction (see fundchannel_complete)."
]
},
"leased": {
"type": "boolean",
"description": [
Expand Down Expand Up @@ -22987,6 +23010,7 @@
"type": "object",
"additionalProperties": false,
"required": [
"psbt",
"local_funds_msat",
"remote_funds_msat"
],
Expand Down Expand Up @@ -23020,6 +23044,20 @@
"description": [
"Amount we were paid by peer at open."
]
},
"psbt": {
"type": "string",
"added": "v25.12",
"description": [
"The PSBT (may be non-final or unsigned) we should use to open the channel, if any. This is initially from `fundchannel_complete`, but will be updated with if `sendpsbt` is called with an updated PSBT."
]
},
"withheld": {
"type": "boolean",
"added": "v25.12",
"description": [
"True if `fundchannel_complete` told us it will not broadcast the funding transaction (so we know not to bother with any other onchain transactions in the case of this channel). This is set to false if `sendpsbt` is send on the above PSBT."
]
}
}
},
Expand Down Expand Up @@ -30987,7 +31025,7 @@
"rpc": "sendpsbt",
"title": "Command to finalize, extract and send a partially signed bitcoin transaction (PSBT).",
"description": [
"The **sendpsbt** is a low-level RPC command which sends a fully-signed PSBT."
"The **sendpsbt** is a low-level RPC command which sends a fully-signed PSBT. If the PSBT is the same one promised by a channel (via fundchannel_complete) it will also be associated with that channel and re-transmitted if necessary on restart."
],
"request": {
"required": [
Expand Down
3 changes: 2 additions & 1 deletion contrib/pyln-client/pyln/client/lightning.py
Original file line number Diff line number Diff line change
Expand Up @@ -844,13 +844,14 @@ def fundchannel_cancel(self, node_id):
}
return self.call("fundchannel_cancel", payload)

def fundchannel_complete(self, node_id, psbt):
def fundchannel_complete(self, node_id, psbt, withhold=True):
"""
Complete channel establishment with {id}, using {psbt}.
"""
payload = {
"id": node_id,
"psbt": psbt,
"withhold": withhold,
}
return self.call("fundchannel_complete", payload)

Expand Down
7 changes: 7 additions & 0 deletions doc/schemas/fundchannel_complete.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@
"description": [
"Transaction to use for funding (does not need to be signed but must be otherwise complete)."
]
},
"withhold": {
"type": "boolean",
"added": "v25.12",
"description": [
"Mark this channel 'withheld' so we know we haven't broadcast the funding transaction. If the channel is closed before we call `sendpsbt` on this psbt, it will simply be closed immediately."
]
}
}
},
Expand Down
16 changes: 16 additions & 0 deletions doc/schemas/listclosedchannels.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
"total_htlcs_sent",
"funding_txid",
"funding_outnum",
"funding_psbt",
"funding_withheld",
"leased",
"final_to_us_msat",
"min_to_us_msat",
Expand Down Expand Up @@ -188,6 +190,20 @@
"The 0-based output number of the funding transaction which opens the channel."
]
},
"funding_psbt": {
"type": "string",
"added": "v25.12",
"description": [
"The PSBT (may be non-final or unsigned) we should use to open the channel, if any"
]
},
"funding_withheld": {
"type": "boolean",
"added": "v25.12",
"description": [
"True if we have not broadcast the funding transaction (see fundchannel_complete)."
]
},
"leased": {
"type": "boolean",
"description": [
Expand Down
15 changes: 15 additions & 0 deletions doc/schemas/listpeerchannels.json
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@
"type": "object",
"additionalProperties": false,
"required": [
"psbt",
"local_funds_msat",
"remote_funds_msat"
],
Expand Down Expand Up @@ -502,6 +503,20 @@
"description": [
"Amount we were paid by peer at open."
]
},
"psbt": {
"type": "string",
"added": "v25.12",
"description": [
"The PSBT (may be non-final or unsigned) we should use to open the channel, if any. This is initially from `fundchannel_complete`, but will be updated with if `sendpsbt` is called with an updated PSBT."
]
},
"withheld": {
"type": "boolean",
"added": "v25.12",
"description": [
"True if `fundchannel_complete` told us it will not broadcast the funding transaction (so we know not to bother with any other onchain transactions in the case of this channel). This is set to false if `sendpsbt` is send on the above PSBT."
]
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion doc/schemas/sendpsbt.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"rpc": "sendpsbt",
"title": "Command to finalize, extract and send a partially signed bitcoin transaction (PSBT).",
"description": [
"The **sendpsbt** is a low-level RPC command which sends a fully-signed PSBT."
"The **sendpsbt** is a low-level RPC command which sends a fully-signed PSBT. If the PSBT is the same one promised by a channel (via fundchannel_complete) it will also be associated with that channel and re-transmitted if necessary on restart."
],
"request": {
"required": [
Expand Down
2 changes: 1 addition & 1 deletion lightningd/bitcoind.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ void bitcoind_sendrawtx_(const tal_t *ctx,
const char *id_prefix TAKES,
const char *hextx,
bool allowhighfees,
void (*cb)(struct bitcoind *bitcoind,
void (*cb)(struct bitcoind *,
bool success, const char *msg, void *),
void *arg);
#define bitcoind_sendrawtx(ctx, bitcoind_, id_prefix, hextx, allowhighfees, cb, arg) \
Expand Down
25 changes: 20 additions & 5 deletions lightningd/channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,8 @@ struct channel *new_unsaved_channel(struct peer *peer,
/* channel->channel_gossip gets populated once we know if it's public. */
channel->channel_gossip = NULL;
channel->forgets = tal_arr(channel, struct command *, 0);
channel->funding_psbt = NULL;
channel->withheld = false;
list_add_tail(&peer->channels, &channel->list);
channel->rr_number = peer->ld->rr_counter++;
tal_add_destructor(channel, destroy_channel);
Expand Down Expand Up @@ -548,7 +550,9 @@ struct channel *new_channel(struct peer *peer, u64 dbid,
struct peer_update *peer_update STEALS,
u64 last_stable_connection,
const struct channel_stats *stats,
struct channel_state_change **state_changes STEALS)
struct channel_state_change **state_changes STEALS,
const struct wally_psbt *funding_psbt STEALS,
bool withheld)
{
struct channel *channel = tal(peer->ld, struct channel);
struct amount_msat htlc_min, htlc_max;
Expand Down Expand Up @@ -748,7 +752,8 @@ struct channel *new_channel(struct peer *peer, u64 dbid,
channel->error = towire_errorfmt(peer->ld,
&channel->cid,
"We can't be together anymore.");

channel->funding_psbt = tal_steal(channel, funding_psbt);
channel->withheld = withheld;
return channel;
}

Expand Down Expand Up @@ -1099,21 +1104,31 @@ static void channel_fail_perm(struct channel *channel,

channel_set_owner(channel, NULL);

if (channel_state_wants_onchain_fail(channel->state))
if (channel->withheld) {
channel_set_state(channel,
channel->state,
CLOSED,
reason,
why);
} else if (channel_state_wants_onchain_fail(channel->state)) {
channel_set_state(channel,
channel->state,
AWAITING_UNILATERAL,
reason,
why);
}

if (channel_state_open_uncommitted(channel->state)) {
delete_channel(channel, false);
return;
}

/* Drop non-cooperatively (unilateral) to chain. If we detect
* the close from the blockchain, then we can observe
* passively, and not broadcast our own unilateral close, as
* it doesn't stand a chance anyway. */
drop_to_chain(ld, channel, false, spent_by);

if (channel_state_open_uncommitted(channel->state))
delete_channel(channel, false);
}

void channel_fail_permanent(struct channel *channel,
Expand Down
10 changes: 9 additions & 1 deletion lightningd/channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,12 @@ struct channel {

/* Our change history. */
struct channel_state_change **state_changes;

/* Unsigned PSBT if we initiated the open channel */
const struct wally_psbt *funding_psbt;

/* Are we not broadcasting the open tx? */
bool withheld;
};

/* Is channel owned (and should be talking to peer) */
Expand Down Expand Up @@ -444,7 +450,9 @@ struct channel *new_channel(struct peer *peer, u64 dbid,
struct peer_update *peer_update STEALS,
u64 last_stable_connection,
const struct channel_stats *stats,
struct channel_state_change **state_changes STEALS);
struct channel_state_change **state_changes STEALS,
const struct wally_psbt *funding_psbt STEALS,
bool withheld);

/* new_inflight - Create a new channel_inflight for a channel */
struct channel_inflight *new_inflight(struct channel *channel,
Expand Down
5 changes: 5 additions & 0 deletions lightningd/channel_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -2405,6 +2405,11 @@ static struct command_result *single_splice_signed(struct command *cmd,
SPLICE_INPUT_ERROR,
"Splice failed to convert to v2");

/* Update "funding" psbt now */
tal_free(channel->funding_psbt);
channel->funding_psbt = clone_psbt(channel, psbt);
wallet_channel_save(cmd->ld->wallet, channel);

msg = towire_channeld_splice_signed(tmpctx, psbt, sign_first);
subd_send_msg(channel->owner, take(msg));
if (success)
Expand Down
2 changes: 2 additions & 0 deletions lightningd/channel_gossip.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ static struct state_transition allowed_transitions[] = {
"Channel usable (zeroconf) but no scid yet" },
{ CGOSSIP_WAITING_FOR_SCID, CGOSSIP_CHANNEL_DEAD,
"Zeroconf channel closed before funding tx mined" },
{ CGOSSIP_WAITING_FOR_SCID, CGOSSIP_CHANNEL_UNANNOUNCED_DYING,
"Zeroconf channel closing mutually before funding tx" },
{ CGOSSIP_WAITING_FOR_USABLE, CGOSSIP_WAITING_FOR_MATCHING_PEER_SIGS,
"Channel mined, but we haven't got matching announcment sigs from peer" },
{ CGOSSIP_WAITING_FOR_USABLE, CGOSSIP_WAITING_FOR_ANNOUNCE_DEPTH,
Expand Down
3 changes: 3 additions & 0 deletions lightningd/closed_channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ static void json_add_closed_channel(struct json_stream *response,
} else if (!amount_msat_is_zero(channel->push))
json_add_amount_msat(response, "funding_pushed_msat",
channel->push);
if (channel->funding_psbt)
json_add_psbt(response, "funding_psbt", channel->funding_psbt);
json_add_bool(response, "funding_withheld", channel->withheld);

json_add_amount_sat_msat(response, "total_msat", channel->funding_sats);
json_add_amount_msat(response, "final_to_us_msat", channel->our_msat);
Expand Down
2 changes: 2 additions & 0 deletions lightningd/closed_channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ struct closed_channel {
u64 last_stable_connection;
/* NULL for older closed channels */
const struct shachain *their_shachain;
const struct wally_psbt *funding_psbt;
bool withheld;
};

static inline const struct channel_id *keyof_closed_channel(const struct closed_channel *cc)
Expand Down
13 changes: 9 additions & 4 deletions lightningd/closing_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,18 @@ static void
resolve_one_close_command(struct close_command *cc, bool cooperative,
const struct bitcoin_tx **close_txs)
{
assert(tal_count(close_txs));
struct json_stream *result = json_stream_success(cc->cmd);
const struct bitcoin_tx *close_tx = close_txs[tal_count(close_txs) - 1];
const struct bitcoin_tx *close_tx;

if (command_deprecated_out_ok(cc->cmd, "tx", "v24.11", "v25.12"))
/* Withheld funding channels can have no close_txs! */
if (tal_count(close_txs) != 0)
close_tx = close_txs[tal_count(close_txs) - 1];
else
close_tx = NULL;

if (close_tx && command_deprecated_out_ok(cc->cmd, "tx", "v24.11", "v25.12"))
json_add_tx(result, "tx", close_tx);
if (!invalid_last_tx(close_tx)) {
if (close_tx && !invalid_last_tx(close_tx)) {
struct bitcoin_txid txid;
bitcoin_txid(close_tx, &txid);
if (command_deprecated_out_ok(cc->cmd, "txid", "v24.11", "v25.12"))
Expand Down
7 changes: 7 additions & 0 deletions lightningd/dual_open_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -1521,6 +1521,8 @@ wallet_commit_channel(struct lightningd *ld,
channel->lease_chan_max_ppt = lease_chan_max_ppt;
channel->htlc_minimum_msat = channel_info->their_config.htlc_minimum;
channel->htlc_maximum_msat = htlc_max_possible_send(channel);
/* Filled in when we have PSBT for inflight */
channel->funding_psbt = NULL;

/* Now we finally put it in the database. */
wallet_channel_insert(ld->wallet, channel);
Expand Down Expand Up @@ -2793,6 +2795,11 @@ json_openchannel_signed(struct command *cmd,
wallet_inflight_save(cmd->ld->wallet, inflight);
watch_opening_inflight(cmd->ld, inflight);

/* Channel's funding psbt also updated now */
tal_free(channel->funding_psbt);
channel->funding_psbt = clone_psbt(channel, inflight->funding_psbt);
wallet_channel_save(cmd->ld->wallet, channel);

/* Only after we've updated/saved our psbt do we check
* for peer connected */
if (!channel->owner)
Expand Down
3 changes: 2 additions & 1 deletion lightningd/lightningd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1449,9 +1449,10 @@ int main(int argc, char *argv[])
plugin_hook_call_recover(ld, NULL, payload);
}

/*~ If we have channels closing, make sure we re-xmit the last
/*~ If we have channels closing or opening, make sure we re-xmit the last
* transaction, in case bitcoind lost it. */
db_begin_transaction(ld->wallet->db);
resend_opening_transactions(ld);
resend_closing_transactions(ld);
db_commit_transaction(ld->wallet->db);

Expand Down
6 changes: 6 additions & 0 deletions lightningd/opening_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ struct funding_channel {
/* Place to stash the per-peer-state while we wait
* for them to get back to us with signatures */
struct peer_fd *peer_fd;

/* Were we the one to publish the commitment/splicing tx? */
const struct wally_psbt *funding_psbt;

/* Were we told to withhold the commitment tx? */
bool withheld;
};

struct uncommitted_channel *new_uncommitted_channel(struct peer *peer);
Expand Down
Loading
Loading