splice: Reestablish when commit or sig sends fail

Adds tests for when the connection fails during
1) splice tx_signature
2) splice commitment_signed

Fleshed out the reestablish flow for these two cases and implemented the fixes to make these reestablish flows work.

Part of this work required changing commit process for splices: Now we send a single commit_part for the splice where previously we sent all commits, and accordingly, we no longer revoke in response.

Changelog-Fixed: Implemented splicing restart logic for tx_signature and commitment_signed. Splice commitments are reworked in a manner incompatible with the last version.
This commit is contained in:
Dusty Daemon 2023-11-02 20:08:33 -04:00 committed by Peter Neuroth
parent eae0d1da1e
commit a6a9e5b1e3
19 changed files with 841 additions and 361 deletions

View File

@ -290,6 +290,27 @@ bool psbt_input_set_signature(struct wally_psbt *psbt, size_t in,
return ok;
}
bool psbt_input_have_signature(const struct wally_psbt *psbt,
size_t in,
const struct pubkey *pubkey,
bool *signature_found)
{
u8 pk_der[PUBKEY_CMPR_LEN];
size_t index_plus_one;
bool ok;
assert(in < psbt->num_inputs);
pubkey_to_der(pk_der, pubkey);
ok = wally_psbt_input_find_signature(&psbt->inputs[in], pk_der,
sizeof(pk_der),
&index_plus_one) == WALLY_OK;
if (ok)
*signature_found = index_plus_one > 0;
return ok;
}
void psbt_input_set_wit_utxo(struct wally_psbt *psbt, size_t in,
const u8 *scriptPubkey, struct amount_sat amt)
{

View File

@ -178,6 +178,14 @@ WARN_UNUSED_RESULT bool psbt_input_set_signature(struct wally_psbt *psbt, size_t
const struct pubkey *pubkey,
const struct bitcoin_signature *sig);
/* Returns false on error. On success, *signature_found is set to true if the
* input has a signature present for `pubkey` and false if if one was not found.
* Only ignature presence is checked, is not validated. */
WARN_UNUSED_RESULT bool psbt_input_have_signature(const struct wally_psbt *psbt,
size_t in,
const struct pubkey *pubkey,
bool *signature_found);
void psbt_input_set_witscript(struct wally_psbt *psbt, size_t in, const u8 *wscript);
/* psbt_input_set_unknown - Set the given Key-Value in the psbt's input keymap

File diff suppressed because it is too large Load Diff

View File

@ -243,6 +243,10 @@ msgtype,channeld_splice_confirmed_signed,7213
msgdata,channeld_splice_confirmed_signed,tx,bitcoin_tx,
msgdata,channeld_splice_confirmed_signed,output_index,u32,
# channeld->master: Splice signatures are about to be sent
msgtype,channeld_splice_sending_sigs,7214
msgdata,channeld_splice_sending_sigs,tx,bitcoin_txid,
# channeld->master: A feerate error has occured
msgtype,channeld_splice_feerate_error,7215
msgdata,channeld_splice_feerate_error,fee,amount_msat,
@ -257,6 +261,7 @@ msgdata,channeld_add_inflight,satoshis,amount_sat,
msgdata,channeld_add_inflight,splice_amount,s64,
msgdata,channeld_add_inflight,psbt,wally_psbt,
msgdata,channeld_add_inflight,i_am_initiator,bool,
msgdata,channeld_add_inflight,force_sign_first,bool,
# master->channeld: Inflight saved successfully
msgtype,channeld_got_inflight,7217

Can't render this file because it has a wrong number of fields in line 15.

View File

@ -10,6 +10,7 @@ struct inflight *fromwire_inflight(const tal_t *ctx, const u8 **cursor, size_t *
fromwire_bitcoin_outpoint(cursor, max, &inflight->outpoint);
inflight->amnt = fromwire_amount_sat(cursor, max);
inflight->remote_tx_sigs = fromwire_bool(cursor, max);
inflight->psbt = fromwire_wally_psbt(inflight, cursor, max);
inflight->splice_amnt = fromwire_s64(cursor, max);
int has_tx = fromwire_u8(cursor, max);
@ -22,6 +23,7 @@ struct inflight *fromwire_inflight(const tal_t *ctx, const u8 **cursor, size_t *
memset(&inflight->last_sig, 0, sizeof(inflight->last_sig));
}
inflight->i_am_initiator = fromwire_bool(cursor, max);
inflight->force_sign_first = fromwire_bool(cursor, max);
return inflight;
}
@ -30,6 +32,7 @@ void towire_inflight(u8 **pptr, const struct inflight *inflight)
{
towire_bitcoin_outpoint(pptr, &inflight->outpoint);
towire_amount_sat(pptr, inflight->amnt);
towire_bool(pptr, inflight->remote_tx_sigs);
towire_wally_psbt(pptr, inflight->psbt);
towire_s64(pptr, inflight->splice_amnt);
towire_u8(pptr, inflight->last_tx ? 1 : 0);
@ -38,15 +41,18 @@ void towire_inflight(u8 **pptr, const struct inflight *inflight)
towire_bitcoin_signature(pptr, &inflight->last_sig);
}
towire_bool(pptr, inflight->i_am_initiator);
towire_bool(pptr, inflight->force_sign_first);
}
void copy_inflight(struct inflight *dest, struct inflight *src)
{
dest->outpoint = src->outpoint;
dest->amnt = src->amnt;
dest->remote_tx_sigs = src->remote_tx_sigs;
dest->psbt = src->psbt ? clone_psbt(dest, src->psbt): NULL;
dest->splice_amnt = src->splice_amnt;
dest->last_tx = src->last_tx ? clone_bitcoin_tx(dest, src->last_tx) : NULL;
dest->last_sig = src->last_sig;
dest->i_am_initiator = src->i_am_initiator;
dest->force_sign_first = src->force_sign_first;
}

View File

@ -8,12 +8,15 @@
struct inflight {
struct bitcoin_outpoint outpoint;
struct amount_sat amnt;
bool remote_tx_sigs;
struct wally_psbt *psbt;
s64 splice_amnt;
struct bitcoin_tx *last_tx;
/* last_sig is assumed valid if last_tx is set */
struct bitcoin_signature last_sig;
bool i_am_initiator;
bool force_sign_first;
bool is_locked;
};
struct inflight *fromwire_inflight(const tal_t *ctx, const u8 **cursor, size_t *max);

View File

@ -6,8 +6,6 @@ struct splice_state *splice_state_new(const tal_t *ctx)
{
struct splice_state *splice_state = tal(ctx, struct splice_state);
splice_state->committed_count = 0;
splice_state->revoked_count = 0;
splice_state->count = 0;
splice_state->locked_ready[LOCAL] = false;
splice_state->locked_ready[REMOTE] = false;

View File

@ -21,10 +21,6 @@ struct splice_state {
bool await_commitment_succcess;
/* The txid of which splice inflight was confirmed */
struct bitcoin_txid locked_txid;
/* The number of splices that have been signed & committed */
u32 committed_count;
/* the number of splices that have been revoke_and_ack'ed */
u32 revoked_count;
/* The number of splices that are active (awaiting confirmation) */
u32 count;
};

View File

@ -124,6 +124,8 @@ psbt_to_witnesses(const tal_t *ctx,
tal_arr(ctx, const struct witness *, 0);
for (size_t i = 0; i < psbt->num_inputs; i++) {
struct wally_tx_witness_stack *wtx_s =
psbt->inputs[i].final_witness;
if (!psbt_get_serial_id(&psbt->inputs[i].unknowns,
&serial_id))
/* FIXME: throw an error ? */
@ -136,9 +138,7 @@ psbt_to_witnesses(const tal_t *ctx,
* - if is the *initiator*:
* - MUST send even `serial_id`s
*/
if (serial_id % 2 == side_to_stack) {
struct wally_tx_witness_stack *wtx_s =
psbt->inputs[i].final_witness;
if (wtx_s && serial_id % 2 == side_to_stack) {
/* BOLT-e299850cb5ebd8bd9c55763bbc498fcdf94a9567 #2:
*

View File

@ -150,7 +150,8 @@ new_inflight(struct channel *channel,
const struct amount_msat lease_fee,
const struct amount_sat lease_amt,
s64 splice_amnt,
bool i_am_initiator)
bool i_am_initiator,
bool force_sign_first)
{
struct channel_inflight *inflight
= tal(channel, struct channel_inflight);
@ -183,6 +184,7 @@ new_inflight(struct channel *channel,
inflight->lease_amt = lease_amt;
inflight->i_am_initiator = i_am_initiator;
inflight->force_sign_first = force_sign_first;
inflight->splice_locked_memonly = false;
list_add_tail(&channel->inflights, &inflight->list);

View File

@ -76,6 +76,9 @@ struct channel_inflight {
/* Did I initate this splice attempt? */
bool i_am_initiator;
/* On reestablish recovery; should I sign first? */
bool force_sign_first;
/* Note: This field is not stored in the database.
*
* After splice_locked, we need a way to stop the chain watchers from
@ -397,7 +400,8 @@ struct channel_inflight *new_inflight(struct channel *channel,
const struct amount_msat lease_fee,
const struct amount_sat lease_amt,
s64 splice_amnt,
bool i_am_initiator);
bool i_am_initiator,
bool force_sign_first);
/* Add a last_tx and sig to an inflight */
void inflight_set_last_tx(struct channel_inflight *inflight,

View File

@ -499,9 +499,7 @@ static void send_splice_tx(struct channel *channel,
send_splice_tx_done, info);
}
/* After user signs PSBT with splice_signed, our node goes through the signing
* process (adding it's own signatures and peers' sigs), sending the result to
* us here: */
/* After channeld have all the signatures it sends the result to us here */
static void handle_splice_confirmed_signed(struct lightningd *ld,
struct channel *channel,
const u8 *msg)
@ -512,7 +510,8 @@ static void handle_splice_confirmed_signed(struct lightningd *ld,
struct channel_inflight *inflight;
u32 output_index;
if (!fromwire_channeld_splice_confirmed_signed(tmpctx, msg, &tx, &output_index)) {
if (!fromwire_channeld_splice_confirmed_signed(tmpctx, msg, &tx,
&output_index)) {
channel_internal_error(channel,
"bad splice_confirmed_signed %s",
@ -532,23 +531,130 @@ static void handle_splice_confirmed_signed(struct lightningd *ld,
inflight->remote_tx_sigs = true;
wallet_inflight_save(ld->wallet, inflight);
if (channel->state != CHANNELD_NORMAL) {
if (channel->state != CHANNELD_AWAITING_SPLICE) {
log_debug(channel->log,
"Would broadcast splice, but state %s"
" isn't CHANNELD_NORMAL",
" isn't CHANNELD_AWAITING_SPLICE",
channel_state_name(channel));
return;
}
cc = splice_command_for_chan(ld, channel);
send_splice_tx(channel, tx, cc, output_index);
}
static enum watch_result splice_depth_cb(struct lightningd *ld,
const struct bitcoin_txid *txid,
const struct bitcoin_tx *tx,
unsigned int depth,
void *param)
{
/* find_txwatch triggers a type warning on inflight, so we do this. */
struct channel_inflight *inflight = param;
struct txlocator *loc;
struct short_channel_id scid;
/* What scid is this giving us? */
loc = wallet_transaction_locate(tmpctx, ld->wallet, txid);
if (!mk_short_channel_id(&scid,
loc->blkheight, loc->index,
inflight->funding->outpoint.n)) {
channel_fail_permanent(inflight->channel,
REASON_LOCAL,
"Invalid funding scid %u:%u:%u",
loc->blkheight, loc->index,
inflight->funding->outpoint.n);
return false;
}
/* Usually, we're here because we're awaiting a splice, but
* we could also mutual shutdown, or that weird splice_locked_memonly
* hack... */
if (inflight->channel->state != CHANNELD_AWAITING_SPLICE) {
log_info(inflight->channel->log, "Splice inflight event but not"
" in AWAITING_SPLICE, ending watch of txid %s",
type_to_string(tmpctx, struct bitcoin_txid, txid));
return DELETE_WATCH;
}
/* Reorged out? OK, we're not committed yet. */
if (depth == 0) {
return KEEP_WATCHING;
}
if (inflight->channel->owner) {
log_info(inflight->channel->log, "splice_depth_cb: sending funding depth scid: %s",
type_to_string(tmpctx, struct short_channel_id, &scid));
subd_send_msg(inflight->channel->owner,
take(towire_channeld_funding_depth(
NULL, &scid,
inflight->channel->alias[LOCAL],
depth, true, txid)));
}
/* channeld will tell us when splice is locked in: we'll clean
* this watch up then. */
return KEEP_WATCHING;
}
void watch_splice_inflight(struct lightningd *ld,
struct channel_inflight *inflight)
{
log_info(inflight->channel->log, "Watching splice inflight %s",
type_to_string(tmpctx, struct bitcoin_txid,
&inflight->funding->outpoint.txid));
watch_txid(inflight, ld->topology,
&inflight->funding->outpoint.txid,
splice_depth_cb, inflight);
}
static struct txwatch *splice_inflight_txwatch(struct channel *channel,
struct channel_inflight *inflight)
{
return find_txwatch(channel->peer->ld->topology,
&inflight->funding->outpoint.txid,
splice_depth_cb, channel);
}
static void handle_splice_sending_sigs(struct lightningd *ld,
struct channel *channel,
const u8 *msg)
{
struct splice_command *cc;
struct bitcoin_txid txid;
struct channel_inflight *inflight;
if (!fromwire_channeld_splice_sending_sigs(msg, &txid)) {
channel_internal_error(channel,
"bad splice_confirmed_signed %s",
tal_hex(channel, msg));
return;
}
inflight = channel_inflight_find(channel, &txid);
if (!inflight)
channel_internal_error(channel, "Unable to load inflight for"
" splice_confirmed_signed txid %s",
type_to_string(tmpctx,
struct bitcoin_txid,
&txid));
/* Signing a splice after it has confirmed is safe and can happen during
* reestablish if one node is late seeing blocks */
if (channel->state == CHANNELD_AWAITING_SPLICE)
return;
cc = splice_command_for_chan(ld, channel);
/* If matching user command found, this was a user intiated splice */
channel_set_state(channel,
CHANNELD_NORMAL,
CHANNELD_AWAITING_SPLICE,
cc ? REASON_USER : REASON_REMOTE,
"Broadcasting splice");
"Splice signatures sent");
send_splice_tx(channel, tx, cc, output_index);
watch_splice_inflight(ld, inflight);
}
bool depthcb_update_scid(struct channel *channel,
@ -600,46 +706,6 @@ bool depthcb_update_scid(struct channel *channel,
return true;
}
static enum watch_result splice_depth_cb(struct lightningd *ld,
const struct bitcoin_txid *txid,
const struct bitcoin_tx *tx,
unsigned int depth,
struct channel_inflight *inflight)
{
/* Usually, we're here because we're awaiting a splice, but
* we could also mutual shutdown, or that weird splice_locked_memonly
* hack... */
if (inflight->channel->state != CHANNELD_AWAITING_SPLICE)
return DELETE_WATCH;
/* Reorged out? OK, we're not committed yet. */
if (depth == 0)
return KEEP_WATCHING;
if (!depthcb_update_scid(inflight->channel, txid, &inflight->funding->outpoint))
return DELETE_WATCH;
if (inflight->channel->owner) {
subd_send_msg(inflight->channel->owner,
take(towire_channeld_funding_depth(
NULL, inflight->channel->scid,
inflight->channel->alias[LOCAL],
depth, true, txid)));
}
/* channeld will tell us when splice is locked in: we'll clean
* this watch up then. */
return KEEP_WATCHING;
}
void watch_splice_inflight(struct lightningd *ld,
struct channel_inflight *inflight)
{
watch_txid(inflight, ld->topology,
&inflight->funding->outpoint.txid,
splice_depth_cb, inflight);
}
static void handle_add_inflight(struct lightningd *ld,
struct channel *channel,
const u8 *msg)
@ -650,7 +716,7 @@ static void handle_add_inflight(struct lightningd *ld,
s64 splice_amnt;
struct wally_psbt *psbt;
struct channel_inflight *inflight;
bool i_am_initiator;
bool i_am_initiator, force_sign_first;
if (!fromwire_channeld_add_inflight(tmpctx,
msg,
@ -660,7 +726,8 @@ static void handle_add_inflight(struct lightningd *ld,
&satoshis,
&splice_amnt,
&psbt,
&i_am_initiator)) {
&i_am_initiator,
&force_sign_first)) {
channel_internal_error(channel,
"bad channel_add_inflight %s",
tal_hex(channel, msg));
@ -681,14 +748,14 @@ static void handle_add_inflight(struct lightningd *ld,
AMOUNT_MSAT(0),
AMOUNT_SAT(0),
splice_amnt,
i_am_initiator);
i_am_initiator,
force_sign_first);
log_debug(channel->log, "lightningd adding inflight with txid %s",
type_to_string(tmpctx, struct bitcoin_txid,
&inflight->funding->outpoint.txid));
wallet_inflight_add(ld->wallet, inflight);
watch_splice_inflight(ld, inflight);
subd_send_msg(channel->owner, take(towire_channeld_got_inflight(NULL)));
}
@ -885,6 +952,7 @@ static void handle_peer_splice_locked(struct channel *channel, const u8 *msg)
s64 splice_amnt;
struct channel_inflight *inflight;
struct bitcoin_txid locked_txid;
struct txwatch *txw;
if (!fromwire_channeld_got_splice_locked(msg, &funding_sats,
&splice_amnt,
@ -922,6 +990,9 @@ static void handle_peer_splice_locked(struct channel *channel, const u8 *msg)
wallet_channel_clear_inflights(channel->peer->ld->wallet, channel);
depthcb_update_scid(channel, &locked_txid,
&inflight->funding->outpoint);
/* That freed watchers in inflights: now watch funding tx */
channel_watch_funding(channel->peer->ld, channel);
@ -934,6 +1005,14 @@ static void handle_peer_splice_locked(struct channel *channel, const u8 *msg)
list_add_tail(&channel->inflights, &inflight->list);
lockin_complete(channel, CHANNELD_AWAITING_SPLICE);
/* Turn off tx watcher for the splice */
txw = splice_inflight_txwatch(channel, inflight);
if (!txw)
log_unusual(channel->log, "Can't unwatch txid %s",
type_to_string(tmpctx, struct bitcoin_txid,
&locked_txid));
tal_free(txw);
}
/* We were informed by channeld that channel is ready (reached mindepth) */
@ -1318,6 +1397,9 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds)
case WIRE_CHANNELD_SPLICE_CONFIRMED_SIGNED:
handle_splice_confirmed_signed(sd->ld, sd->channel, msg);
break;
case WIRE_CHANNELD_SPLICE_SENDING_SIGS:
handle_splice_sending_sigs(sd->ld, sd->channel, msg);
break;
case WIRE_CHANNELD_ADD_INFLIGHT:
handle_add_inflight(sd->ld, sd->channel, msg);
break;
@ -1524,6 +1606,7 @@ bool peer_start_channeld(struct channel *channel,
infcopy->outpoint = inflight->funding->outpoint;
infcopy->amnt = inflight->funding->total_funds;
infcopy->remote_tx_sigs = inflight->remote_tx_sigs;
infcopy->splice_amnt = inflight->funding->splice_amnt;
if (inflight->last_tx)
infcopy->last_tx = tal_dup(infcopy, struct bitcoin_tx, inflight->last_tx);
@ -1531,9 +1614,12 @@ bool peer_start_channeld(struct channel *channel,
infcopy->last_tx = NULL;
infcopy->last_sig = inflight->last_sig;
infcopy->i_am_initiator = inflight->i_am_initiator;
infcopy->force_sign_first = inflight->force_sign_first;
tal_wally_start();
wally_psbt_clone_alloc(inflight->funding_psbt, 0, &infcopy->psbt);
tal_wally_end_onto(infcopy, infcopy->psbt, struct wally_psbt);
tal_arr_expand(&inflights, infcopy);
}
@ -1643,7 +1729,7 @@ void channeld_tell_depth(struct channel *channel,
subd_send_msg(channel->owner,
take(towire_channeld_funding_depth(
NULL, channel->scid, channel->alias[LOCAL], depth,
channel->state == CHANNELD_AWAITING_SPLICE, txid)));
false, txid)));
}
/* Check if we are the fundee of this channel, the channel

View File

@ -1292,6 +1292,7 @@ wallet_update_channel(struct lightningd *ld,
channel->push,
lease_amt,
0,
false,
false);
wallet_inflight_add(ld->wallet, inflight);
@ -1510,6 +1511,7 @@ wallet_commit_channel(struct lightningd *ld,
channel->push,
lease_amt,
0,
false,
false);
wallet_inflight_add(ld->wallet, inflight);

View File

@ -211,13 +211,14 @@ def test_invalid_splice(node_factory, bitcoind):
result = l1.rpc.signpsbt(result['psbt'])
result = l1.rpc.splice_signed(chan_id, result['signed_psbt'])
l2.daemon.wait_for_log(r'CHANNELD_NORMAL to CHANNELD_AWAITING_SPLICE')
l1.daemon.wait_for_log(r'CHANNELD_NORMAL to CHANNELD_AWAITING_SPLICE')
mempool = bitcoind.rpc.getrawmempool(True)
assert len(list(mempool.keys())) == 1
assert result['txid'] in list(mempool.keys())
# Wait until nodes are reconnected
l1.daemon.wait_for_log(r'peer_in WIRE_CHANNEL_REESTABLISH')
l2.daemon.wait_for_log(r'peer_in WIRE_CHANNEL_REESTABLISH')
bitcoind.generate_block(6, wait_for_mempool=1)
l2.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL')

View File

@ -0,0 +1,119 @@
from fixtures import * # noqa: F401,F403
import pytest
import unittest
import time
from pyln.testing.utils import EXPERIMENTAL_DUAL_FUND
from utils import (
TEST_NETWORK, first_scid
)
@pytest.mark.openchannel('v1')
@pytest.mark.openchannel('v2')
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
def test_splice_disconnect_sig(node_factory, bitcoind):
# Dual open and splicing both use tx_sig messages. If we have dual enabled, ignore the first one.
disconnect = ['-WIRE_TX_SIGNATURES']
if EXPERIMENTAL_DUAL_FUND:
disconnect = ['=WIRE_TX_SIGNATURES'] + disconnect
l1 = node_factory.get_node(disconnect=disconnect,
options={'experimental-splicing': None, 'dev-no-reconnect': None},
may_reconnect=True)
l2 = node_factory.get_node(options={'experimental-splicing': None}, may_reconnect=True)
l1.openchannel(l2, 1000000)
chan_id = l1.get_channel_id(l2)
# add extra sats to pay fee
funds_result = l1.rpc.fundpsbt("109000sat", "slow", 166, excess_as_change=True)
result = l1.rpc.splice_init(chan_id, 100000, funds_result['psbt'])
result = l1.rpc.splice_update(chan_id, result['psbt'])
result = l1.rpc.signpsbt(result['psbt'])
result = l1.rpc.splice_signed(chan_id, result['signed_psbt'])
l1.daemon.wait_for_log(r'dev_disconnect: \-WIRE_TX_SIGNATURES')
print("Killing l1 without sending WIRE_TX_SIGNATURES")
l1.daemon.kill()
# Restart l1, without disconnect stuff.
del l1.daemon.opts['dev-no-reconnect']
del l1.daemon.opts['dev-disconnect']
# Should reconnect, and reestablish the splice.
l1.start()
# Wait until nodes are reconnected
l1.daemon.wait_for_log(r'peer_in WIRE_CHANNEL_REESTABLISH')
l2.daemon.wait_for_log(r'peer_in WIRE_CHANNEL_REESTABLISH')
bitcoind.generate_block(6, wait_for_mempool=1)
l1.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL')
l2.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL')
l1.daemon.wait_for_log(r'private channel announcement from channeld for ' + first_scid(l1, l2))
inv = l2.rpc.invoice(10**2, '3', 'no_3')
l1.rpc.pay(inv['bolt11'])
# Check that the splice doesn't generate a unilateral close transaction
time.sleep(5)
assert l1.db_query("SELECT count(*) as c FROM channeltxs;")[0]['c'] == 0
@pytest.mark.openchannel('v1')
@pytest.mark.openchannel('v2')
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
def test_splice_disconnect_commit(node_factory, bitcoind, executor):
l1 = node_factory.get_node(options={'experimental-splicing': None}, may_reconnect=True)
l2 = node_factory.get_node(disconnect=['+WIRE_COMMITMENT_SIGNED'],
options={'experimental-splicing': None, 'dev-no-reconnect': None},
may_reconnect=True)
l1.openchannel(l2, 1000000)
chan_id = l1.get_channel_id(l2)
# add extra sats to pay fee
funds_result = l1.rpc.fundpsbt("109000sat", "slow", 166, excess_as_change=True)
result = l1.rpc.splice_init(chan_id, 100000, funds_result['psbt'])
print("l1 splice_update")
result = l1.rpc.splice_update(chan_id, result['psbt'])
print("l1 signpsbt")
result = l1.rpc.signpsbt(result['psbt'])
print("l1 splice_signed")
executor.submit(l1.rpc.splice_signed, chan_id, result['signed_psbt'])
print("l2 waiting for dev_disconnect msg")
l2.daemon.wait_for_log(r'dev_disconnect: \+WIRE_COMMITMENT_SIGNED')
print("Killing l2 without sending WIRE_COMMITMENT_SIGNED")
l2.daemon.kill()
# Restart l1, without disconnect stuff.
del l2.daemon.opts['dev-no-reconnect']
del l2.daemon.opts['dev-disconnect']
# Should reconnect, and reestablish the splice.
l2.start()
# Wait until nodes are reconnected
l1.daemon.wait_for_log(r'peer_in WIRE_CHANNEL_REESTABLISH')
l2.daemon.wait_for_log(r'peer_in WIRE_CHANNEL_REESTABLISH')
bitcoind.generate_block(6, wait_for_mempool=1)
l1.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL')
l2.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL')
l1.daemon.wait_for_log(r'private channel announcement from channeld for ' + first_scid(l1, l2))
inv = l2.rpc.invoice(10**2, '3', 'no_3')
l1.rpc.pay(inv['bolt11'])
# Check that the splice doesn't generate a unilateral close transaction
time.sleep(5)
assert l1.db_query("SELECT count(*) as c FROM channeltxs;")[0]['c'] == 0

View File

@ -1010,6 +1010,7 @@ static struct migration dbmigrations[] = {
{SQL("ALTER TABLE forwards ADD updated_index BIGINT DEFAULT 0"), NULL},
{SQL("CREATE INDEX forwards_updated_idx ON forwards (updated_index)"), NULL},
{NULL, migrate_initialize_forwards_wait_indexes},
{SQL("ALTER TABLE channel_funding_inflights ADD force_sign_first INTEGER DEFAULT 0"), NULL},
};
/**

View File

@ -201,7 +201,8 @@ struct channel_inflight *new_inflight(struct channel *channel UNNEEDED,
const struct amount_msat lease_fee UNNEEDED,
const struct amount_sat lease_amt UNNEEDED,
s64 splice_amnt UNNEEDED,
bool i_am_initiator UNNEEDED)
bool i_am_initiator UNNEEDED,
bool force_sign_first UNNEEDED)
{ fprintf(stderr, "new_inflight called!\n"); abort(); }
/* Generated stub for new_logger */
struct logger *new_logger(const tal_t *ctx UNNEEDED, struct log_book *record UNNEEDED,

View File

@ -1923,6 +1923,7 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx)
AMOUNT_MSAT(10),
AMOUNT_SAT(1111),
0,
false,
false);
inflight_set_last_tx(inflight, last_tx, sig);
@ -1949,6 +1950,7 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx)
AMOUNT_MSAT(0),
AMOUNT_SAT(0),
0,
false,
false);
inflight_set_last_tx(inflight, last_tx, sig);
wallet_inflight_add(w, inflight);

View File

@ -1217,8 +1217,9 @@ void wallet_inflight_add(struct wallet *w, struct channel_inflight *inflight)
", lease_satoshi"
", splice_amnt"
", i_am_initiator"
", force_sign_first"
") VALUES ("
"?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"));
"?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"));
db_bind_u64(stmt, inflight->channel->dbid);
db_bind_txid(stmt, &inflight->funding->outpoint.txid);
@ -1256,6 +1257,7 @@ void wallet_inflight_add(struct wallet *w, struct channel_inflight *inflight)
db_bind_s64(stmt, inflight->funding->splice_amnt);
db_bind_int(stmt, inflight->i_am_initiator);
db_bind_int(stmt, inflight->force_sign_first);
db_exec_prepared_v2(stmt);
assert(!stmt->error);
@ -1324,7 +1326,7 @@ wallet_stmt2inflight(struct wallet *w, struct db_stmt *stmt,
struct bitcoin_tx *last_tx;
struct channel_inflight *inflight;
s64 splice_amnt;
bool i_am_initiator;
bool i_am_initiator, force_sign_first;
secp256k1_ecdsa_signature *lease_commit_sig;
u32 lease_blockheight_start;
@ -1362,6 +1364,7 @@ wallet_stmt2inflight(struct wallet *w, struct db_stmt *stmt,
splice_amnt = db_col_s64(stmt, "splice_amnt");
i_am_initiator = db_col_int(stmt, "i_am_initiator");
force_sign_first = db_col_int(stmt, "force_sign_first");
inflight = new_inflight(chan, &funding,
db_col_int(stmt, "funding_feerate"),
@ -1376,7 +1379,8 @@ wallet_stmt2inflight(struct wallet *w, struct db_stmt *stmt,
lease_fee,
lease_amt,
splice_amnt,
i_am_initiator);
i_am_initiator,
force_sign_first);
/* last_tx is null for not yet committed
* channels + static channel backup recoveries */
@ -1427,6 +1431,7 @@ static bool wallet_channel_load_inflights(struct wallet *w,
", lease_satoshi"
", splice_amnt"
", i_am_initiator"
", force_sign_first"
" FROM channel_funding_inflights"
" WHERE channel_id = ?"
" ORDER BY funding_feerate"));