lightningd: fold funding tx depth into a single function.

Currently it's half done in funding_depth_cb, and half in
channeld_tell_depth.  It's very confusing as a result,
with splicing, dual-funding and zeroconf.

This does introduce a behaviour change: if a channel is NORMAL and
it gets reorganized, we force close (unless we were the one who funded
it, or it's zeroconf anyway).  This is safer than continuing to use
the channel in this case!

Some tests are changed to zeroconf to make them work, but v2 doesn't
support zeroconf, so that's removed.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2023-10-02 09:29:49 +10:30
parent c0ffb17661
commit 2de7171286
6 changed files with 277 additions and 266 deletions

View File

@ -721,8 +721,25 @@ void channel_record_open(struct channel *channel, u32 blockheight, bool record_p
channel->opener == REMOTE));
}
static void lockin_complete(struct channel *channel,
enum channel_state expected_state)
void lockin_has_completed(struct channel *channel, bool record_push)
{
/* Fees might have changed (and we use IMMEDIATE once we're funded),
* so update now. */
try_update_feerates(channel->peer->ld, channel);
try_update_blockheight(channel->peer->ld, channel,
get_block_height(channel->peer->ld->topology));
/* Emit an event for the channel open (or channel proposal if blockheight
* is zero) */
channel_record_open(channel,
channel->scid ?
short_channel_id_blocknum(channel->scid) : 0,
record_push);
}
void lockin_complete(struct channel *channel,
enum channel_state expected_state)
{
if (!channel->scid &&
(!channel->alias[REMOTE] || !channel->alias[LOCAL])) {
@ -751,19 +768,7 @@ static void lockin_complete(struct channel *channel,
REASON_UNKNOWN,
"Lockin complete");
/* Fees might have changed (and we use IMMEDIATE once we're funded),
* so update now. */
try_update_feerates(channel->peer->ld, channel);
try_update_blockheight(channel->peer->ld, channel,
get_block_height(channel->peer->ld->topology));
/* Emit an event for the channel open (or channel proposal if blockheight
* is zero) */
channel_record_open(channel,
channel->scid ?
short_channel_id_blocknum(channel->scid) : 0,
true);
lockin_has_completed(channel, true);
}
bool channel_on_channel_ready(struct channel *channel,
@ -1113,22 +1118,6 @@ static void handle_channel_upgrade(struct channel *channel,
wallet_channel_save(channel->peer->ld->wallet, channel);
}
static bool get_inflight_outpoint_index(struct channel *channel,
const struct bitcoin_txid *txid,
u32 *index)
{
struct channel_inflight *inflight;
list_for_each(&channel->inflights, inflight, list) {
if (bitcoin_txid_eq(txid, &inflight->funding->outpoint.txid)) {
*index = inflight->funding->outpoint.n;
return true;
}
}
return false;
}
static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds)
{
enum channeld_wire t = fromwire_peektype(msg);
@ -1515,47 +1504,18 @@ bool peer_start_channeld(struct channel *channel,
return true;
}
static bool channel_splice_set_scid(struct channel *channel,
const struct bitcoin_txid *txid)
{
struct txlocator *loc;
u32 outnum;
if (!get_inflight_outpoint_index(channel, txid, &outnum)) {
log_debug(channel->log, "Can't locate splice inflight"
" txid %s",
type_to_string(tmpctx, struct bitcoin_txid, txid));
return false;
}
loc = wallet_transaction_locate(tmpctx, channel->peer->ld->wallet, txid);
if (!loc) {
channel_fail_permanent(channel,
REASON_LOCAL,
"Can't locate splice transaction"
" in wallet txid %s",
type_to_string(tmpctx, struct bitcoin_txid, txid));
return false;
}
if (!mk_short_channel_id(channel->scid,
loc->blkheight, loc->index,
outnum)) {
channel_fail_permanent(channel,
REASON_LOCAL,
"Invalid splice scid %u:%u:%u",
loc->blkheight, loc->index,
channel->funding.n);
return false;
}
return true;
}
/* Actually send the depth message to channeld */
static void channeld_tell_depth(struct channel *channel,
const struct bitcoin_txid *txid,
u32 depth)
void channeld_tell_depth(struct channel *channel,
const struct bitcoin_txid *txid,
u32 depth)
{
if (!channel->owner) {
log_debug(channel->log,
"Funding tx %s confirmed, but peer disconnected",
type_to_string(tmpctx, struct bitcoin_txid, txid));
return;
}
log_debug(channel->log,
"Sending towire_channeld_funding_depth with channel state %s",
channel_state_str(channel->state));
@ -1566,95 +1526,6 @@ static void channeld_tell_depth(struct channel *channel,
channel->state == CHANNELD_AWAITING_SPLICE, txid)));
}
bool channel_tell_depth(struct lightningd *ld,
struct channel *channel,
const struct bitcoin_txid *txid,
u32 depth)
{
const char *txidstr;
txidstr = type_to_string(tmpctx, struct bitcoin_txid, txid);
channel->depth = depth;
if (!channel->owner) {
log_debug(channel->log,
"Funding tx %s confirmed, but peer disconnected",
txidstr);
return false;
}
switch (channel->state) {
case CHANNELD_AWAITING_SPLICE:
/* Once we're waiting for splice, don't watch original any more */
if (bitcoin_txid_eq(txid, &channel->funding.txid))
return true;
if (depth >= channel->minimum_depth) {
if (!channel_splice_set_scid(channel, txid))
return false;
}
channeld_tell_depth(channel, txid, depth);
/* We're done, don't track depth any more. */
return true;
case DUALOPEND_AWAITING_LOCKIN:
log_debug(channel->log,
"Funding tx %s confirmed, telling peer", txidstr);
dualopend_tell_depth(channel,
txid, depth);
/* We're done, don't track depth any more. */
return true;
case CHANNELD_AWAITING_LOCKIN:
channeld_tell_depth(channel, txid, depth);
if (channel->remote_channel_ready
&& depth >= channel->minimum_depth) {
lockin_complete(channel, CHANNELD_AWAITING_LOCKIN);
return true;
}
return false;
case CHANNELD_NORMAL:
/* If we have a zeroconf channel, i.e., no scid yet
* but have exchange `channel_ready` messages, then we
* need to fire a second time, in order to trigger the
* `coin_movement` event. This is a subset of the
* `lockin_complete` function above. */
if (depth == 1 && channel->minimum_depth == 0) {
assert(channel->scid != NULL);
/* Fees might have changed (and we use IMMEDIATE once we're
* funded), so update now. */
try_update_feerates(channel->peer->ld, channel);
try_update_blockheight(
channel->peer->ld, channel,
get_block_height(channel->peer->ld->topology));
/* Emit channel_open event */
channel_record_open(channel,
short_channel_id_blocknum(channel->scid),
false);
}
/* Still might want to know, for announcement reasons */
channeld_tell_depth(channel, txid, depth);
return false;
case AWAITING_UNILATERAL:
case CHANNELD_SHUTTING_DOWN:
case CLOSINGD_SIGEXCHANGE:
case CLOSINGD_COMPLETE:
case FUNDING_SPEND_SEEN:
case ONCHAIN:
case CLOSED:
case DUALOPEND_OPEN_INIT:
/* If not awaiting lockin/announce, it doesn't care any more */
log_debug(channel->log,
"Funding tx %s confirmed, but peer in state %s",
txidstr, channel_state_name(channel));
return true;
}
abort();
}
/* Check if we are the fundee of this channel, the channel
* funding transaction is still not yet seen onchain, and
* it has been too long since the channel was first opened.

View File

@ -16,11 +16,12 @@ bool peer_start_channeld(struct channel *channel,
bool reconnected,
bool reestablish_only);
/* Returns true if subd told, otherwise false. */
bool channel_tell_depth(struct lightningd *ld,
struct channel *channel,
const struct bitcoin_txid *txid,
u32 depth);
/* Send message to channeld (if connected) to tell it about depth
* c.f. dualopen_tell_depth! */
void channeld_tell_depth(struct channel *channel,
const struct bitcoin_txid *txid,
u32 depth);
/* Notify channels of new blocks. */
void channel_notify_new_block(struct lightningd *ld,
u32 block_height);
@ -45,4 +46,11 @@ void channel_replace_update(struct channel *channel, u8 *update TAKES);
/* Tell channel about new feerates (owner must be channeld!) */
void channel_update_feerates(struct lightningd *ld, const struct channel *channel);
/* This channel is now locked in (the normal way, not zeroconf) */
void lockin_complete(struct channel *channel,
enum channel_state expected_state);
/* Accessor for zeroconf to tell us we've actually got an scid */
void lockin_has_completed(struct channel *channel, bool record_push);
#endif /* LIGHTNING_LIGHTNINGD_CHANNEL_CONTROL_H */

View File

@ -1829,18 +1829,50 @@ void update_channel_from_inflight(struct lightningd *ld,
wallet_channel_save(ld->wallet, channel);
}
static void subd_tell_depth(struct channel *channel,
const struct bitcoin_txid *txid,
unsigned int depth)
{
/* We always tell every owner who's interested about the depth */
switch (channel->state) {
case AWAITING_UNILATERAL:
case CHANNELD_SHUTTING_DOWN:
case CLOSINGD_SIGEXCHANGE:
case CLOSINGD_COMPLETE:
case FUNDING_SPEND_SEEN:
case ONCHAIN:
case CLOSED:
case DUALOPEND_OPEN_INIT:
return;
case CHANNELD_NORMAL:
case CHANNELD_AWAITING_LOCKIN:
case CHANNELD_AWAITING_SPLICE:
channeld_tell_depth(channel, txid, depth);
return;
case DUALOPEND_AWAITING_LOCKIN:
dualopend_tell_depth(channel, txid, depth);
return;
}
abort();
}
static enum watch_result funding_depth_cb(struct lightningd *ld,
struct channel *channel,
const struct bitcoin_txid *txid,
const struct bitcoin_tx *tx,
unsigned int depth)
{
const char *txidstr;
struct short_channel_id scid;
struct txlocator *loc;
/* Sanity check, but we'll have to make an exception
* for stub channels(1x1x1) */
if (!check_funding_tx(tx, channel) && !is_stub_scid(channel->scid)) {
/* This is stub channel, we don't activate anything! */
if (is_stub_scid(channel->scid))
return DELETE_WATCH;
/* Sanity check */
if (!check_funding_tx(tx, channel)) {
channel_internal_error(channel, "Bad tx %s: %s",
type_to_string(tmpctx,
struct bitcoin_txid, txid),
@ -1849,102 +1881,162 @@ static enum watch_result funding_depth_cb(struct lightningd *ld,
return DELETE_WATCH;
}
txidstr = type_to_string(tmpctx, struct bitcoin_txid, txid);
channel->depth = depth;
log_debug(channel->log, "Funding tx %s depth %u of %u",
txidstr, depth, channel->minimum_depth);
tal_free(txidstr);
type_to_string(tmpctx, struct bitcoin_txid, txid),
depth, channel->minimum_depth);
bool min_depth_reached = depth >= channel->minimum_depth;
bool min_depth_no_scid = min_depth_reached && !channel->scid;
bool some_depth_has_scid = depth != 0 && channel->scid;
/* Reorged out? */
if (depth == 0) {
/* That's not entirely unexpected in early states */
switch (channel->state) {
case CHANNELD_AWAITING_SPLICE:
case DUALOPEND_AWAITING_LOCKIN:
case CHANNELD_AWAITING_LOCKIN:
case DUALOPEND_OPEN_INIT:
log_debug(channel->log, "Funding tx %s reorganized out!",
type_to_string(tmpctx, struct bitcoin_txid, txid));
channel->scid = tal_free(channel->scid);
return KEEP_WATCHING;
/* Reorg can change scid, so always update/save scid when possible (depth=0
* means the stale block with our funding tx was removed) */
if (min_depth_no_scid || some_depth_has_scid) {
struct txlocator *loc;
struct channel_inflight *inf;
/* But it's often Bad News in later states */
case CHANNELD_NORMAL:
/* If we opened, or it's zero-conf, we trust them anyway. */
if (channel->opener == LOCAL
|| channel->minimum_depth == 0) {
const char *str;
str = tal_fmt(tmpctx,
"Funding tx %s reorganized out, but %s...",
type_to_string(tmpctx, struct bitcoin_txid, txid),
channel->opener == LOCAL ? "we opened it" : "zeroconf anyway");
/* Log even if not connected! */
if (!channel->owner)
log_info(channel->log, "%s", str);
channel_fail_transient(channel, true, "%s", str);
return KEEP_WATCHING;
}
/* fall thru */
case AWAITING_UNILATERAL:
case CHANNELD_SHUTTING_DOWN:
case CLOSINGD_SIGEXCHANGE:
case CLOSINGD_COMPLETE:
case FUNDING_SPEND_SEEN:
case ONCHAIN:
case CLOSED:
break;
}
channel_internal_error(channel,
"Funding transaction has been reorged out in state %s!",
channel_state_name(channel));
return KEEP_WATCHING;
}
/* What scid is this giving us? */
loc = wallet_transaction_locate(tmpctx, ld->wallet, txid);
if (!mk_short_channel_id(&scid,
loc->blkheight, loc->index,
channel->funding.n)) {
channel_fail_permanent(channel,
REASON_LOCAL,
"Invalid funding scid %u:%u:%u",
loc->blkheight, loc->index,
channel->funding.n);
return DELETE_WATCH;
}
if (!channel->scid) {
wallet_annotate_txout(ld->wallet, &channel->funding,
TX_CHANNEL_FUNDING, channel->dbid);
channel->scid = tal_dup(channel, struct short_channel_id, &scid);
/* If we have a zeroconf channel, i.e., no scid yet
* but have exchange `channel_ready` messages, then we
* need to fire a second time, in order to trigger the
* `coin_movement` event. This is a subset of the
* `lockin_complete` function called from
* AWAITING_LOCKIN->NORMAL otherwise. */
if (channel->minimum_depth == 0)
lockin_has_completed(channel, false);
wallet_channel_save(ld->wallet, channel);
} else if (!short_channel_id_eq(channel->scid, &scid)) {
/* We freaked out if required when original was
* removed, so just update now */
log_info(channel->log, "Short channel id changed from %s->%s",
type_to_string(tmpctx, struct short_channel_id, channel->scid),
type_to_string(tmpctx, struct short_channel_id, &scid));
*channel->scid = scid;
wallet_channel_save(ld->wallet, channel);
}
/* Always tell owner about depth change */
subd_tell_depth(channel, txid, depth);
/* Have we not reached minimum depth? */
if (depth < channel->minimum_depth)
return KEEP_WATCHING;
switch (channel->state) {
case AWAITING_UNILATERAL:
case CHANNELD_SHUTTING_DOWN:
case CLOSINGD_SIGEXCHANGE:
case CLOSINGD_COMPLETE:
case FUNDING_SPEND_SEEN:
case ONCHAIN:
case CLOSED:
/* If not awaiting lockin/announce, it doesn't care any more */
log_debug(channel->log,
"Funding tx %s confirmed, but peer in state %s",
type_to_string(tmpctx, struct bitcoin_txid, txid),
channel_state_name(channel));
return DELETE_WATCH;
case CHANNELD_AWAITING_LOCKIN:
if (channel->remote_channel_ready)
lockin_complete(channel, CHANNELD_AWAITING_LOCKIN);
return KEEP_WATCHING;
case CHANNELD_NORMAL:
if (depth < ANNOUNCE_MIN_DEPTH)
return KEEP_WATCHING;
/* Normal state and past announce depth? Stop bothering us! */
return DELETE_WATCH;
case DUALOPEND_OPEN_INIT:
/* You cannot be watching yet */
abort();
case DUALOPEND_AWAITING_LOCKIN:
/* Update the channel's info to the correct tx, if needed to
* It's possible an 'inflight' has reached depth */
if (channel->state != CHANNELD_AWAITING_SPLICE
&& !list_empty(&channel->inflights)) {
if (!list_empty(&channel->inflights)) {
struct channel_inflight *inf;
inf = channel_inflight_find(channel, txid);
if (!inf) {
log_debug(channel->log,
"Ignoring event for txid %s for channel"
" not found in inflights. (peer %s)",
type_to_string(tmpctx,
struct bitcoin_txid,
txid),
type_to_string(tmpctx,
struct node_id,
&channel->peer->id));
"Ignoring event for txid %s for channel"
" not found in inflights.",
type_to_string(tmpctx,
struct bitcoin_txid,
txid));
return DELETE_WATCH;
}
update_channel_from_inflight(ld, channel, inf);
}
return KEEP_WATCHING;
wallet_annotate_txout(ld->wallet, &channel->funding,
TX_CHANNEL_FUNDING, channel->dbid);
loc = wallet_transaction_locate(tmpctx, ld->wallet, txid);
if (!mk_short_channel_id(&scid,
loc->blkheight, loc->index,
channel->funding.n)) {
channel_fail_permanent(channel,
REASON_LOCAL,
"Invalid funding scid %u:%u:%u",
loc->blkheight, loc->index,
channel->funding.n);
return DELETE_WATCH;
}
/* If we restart, we could already have peer->scid from database,
* we don't need to update scid for stub channels(1x1x1) */
if (!channel->scid || channel->state == CHANNELD_AWAITING_SPLICE) {
if(!channel->scid)
channel->scid = tal(channel, struct short_channel_id);
*channel->scid = scid;
wallet_channel_save(ld->wallet, channel);
} else if (!short_channel_id_eq(channel->scid, &scid) &&
!is_stub_scid(channel->scid)) {
/* Send warning: that will make connectd disconnect, and then we'll
* try to reconnect. */
u8 *warning = towire_warningfmt(tmpctx, &channel->cid,
"short_channel_id changed to %s (was %s)",
short_channel_id_to_str(tmpctx, &scid),
short_channel_id_to_str(tmpctx, channel->scid));
if (channel->peer->connected != PEER_DISCONNECTED)
subd_send_msg(ld->connectd,
take(towire_connectd_peer_final_msg(NULL,
&channel->peer->id,
channel->peer->connectd_counter,
warning)));
/* When we restart channeld, it will be initialized with updated scid
* and also adds it (at least our halve_chan) to rtable. */
channel_fail_transient(channel, true,
"short_channel_id changed to %s (was %s)",
short_channel_id_to_str(tmpctx, &scid),
short_channel_id_to_str(tmpctx, channel->scid));
*channel->scid = scid;
wallet_channel_save(ld->wallet, channel);
return KEEP_WATCHING;
}
case CHANNELD_AWAITING_SPLICE:
/* Once we're waiting for splice, don't watch original any more */
if (bitcoin_txid_eq(txid, &channel->funding.txid))
return true;
return KEEP_WATCHING;
}
/* Try to tell subdaemon */
if (!channel_tell_depth(ld, channel, txid, depth))
return KEEP_WATCHING;
if (!min_depth_reached)
return KEEP_WATCHING;
/* We keep telling it depth/scid until we get to announce depth. */
if (depth < ANNOUNCE_MIN_DEPTH)
return KEEP_WATCHING;
return DELETE_WATCH;
abort();
}
static enum watch_result funding_spent(struct channel *channel,

View File

@ -110,12 +110,6 @@ const char *channel_state_name(const struct channel *channel UNNEEDED)
/* Generated stub for channel_state_str */
const char *channel_state_str(enum channel_state state UNNEEDED)
{ fprintf(stderr, "channel_state_str called!\n"); abort(); }
/* Generated stub for channel_tell_depth */
bool channel_tell_depth(struct lightningd *ld UNNEEDED,
struct channel *channel UNNEEDED,
const struct bitcoin_txid *txid UNNEEDED,
u32 depth UNNEEDED)
{ fprintf(stderr, "channel_tell_depth called!\n"); abort(); }
/* Generated stub for channel_type_has */
bool channel_type_has(const struct channel_type *type UNNEEDED, int feature UNNEEDED)
{ fprintf(stderr, "channel_type_has called!\n"); abort(); }
@ -133,6 +127,11 @@ void channel_update_reserve(struct channel *channel UNNEEDED,
struct channel_config *their_config UNNEEDED,
struct amount_sat funding_total UNNEEDED)
{ fprintf(stderr, "channel_update_reserve called!\n"); abort(); }
/* Generated stub for channeld_tell_depth */
void channeld_tell_depth(struct channel *channel UNNEEDED,
const struct bitcoin_txid *txid UNNEEDED,
u32 depth UNNEEDED)
{ fprintf(stderr, "channeld_tell_depth called!\n"); abort(); }
/* Generated stub for cmd_id_from_close_command */
const char *cmd_id_from_close_command(const tal_t *ctx UNNEEDED,
struct lightningd *ld UNNEEDED, struct channel *channel UNNEEDED)
@ -202,6 +201,11 @@ void delete_channel(struct channel *channel STEALS UNNEEDED)
/* Generated stub for dev_disconnect_permanent */
bool dev_disconnect_permanent(struct lightningd *ld UNNEEDED)
{ fprintf(stderr, "dev_disconnect_permanent called!\n"); abort(); }
/* Generated stub for dualopend_tell_depth */
void dualopend_tell_depth(struct channel *channel UNNEEDED,
const struct bitcoin_txid *txid UNNEEDED,
u32 depth UNNEEDED)
{ fprintf(stderr, "dualopend_tell_depth called!\n"); abort(); }
/* Generated stub for encode_scriptpubkey_to_addr */
char *encode_scriptpubkey_to_addr(const tal_t *ctx UNNEEDED,
const struct chainparams *chainparams UNNEEDED,
@ -646,6 +650,13 @@ struct jsonrpc_request *jsonrpc_request_start_(
void kill_uncommitted_channel(struct uncommitted_channel *uc UNNEEDED,
const char *why UNNEEDED)
{ fprintf(stderr, "kill_uncommitted_channel called!\n"); abort(); }
/* Generated stub for lockin_complete */
void lockin_complete(struct channel *channel UNNEEDED,
enum channel_state expected_state UNNEEDED)
{ fprintf(stderr, "lockin_complete called!\n"); abort(); }
/* Generated stub for lockin_has_completed */
void lockin_has_completed(struct channel *channel UNNEEDED, bool record_push UNNEEDED)
{ fprintf(stderr, "lockin_has_completed called!\n"); abort(); }
/* Generated stub for log_ */
void log_(struct logger *logger UNNEEDED, enum log_level level UNNEEDED,
const struct node_id *node_id UNNEEDED,

View File

@ -1241,7 +1241,6 @@ def chan_active(node, scid, is_active):
return [c['active'] for c in chans] == [is_active, is_active]
@pytest.mark.openchannel('v2')
@pytest.mark.openchannel('v1')
def test_funding_reorg_private(node_factory, bitcoind):
"""Change funding tx height after lockin, between node restart.
@ -1253,7 +1252,10 @@ def test_funding_reorg_private(node_factory, bitcoind):
# gossipd send lightning update for original channel.
'allow_broken_log': True,
'allow_warning': True,
'dev-fast-reconnect': None}
'dev-fast-reconnect': None,
# if it's not zeroconf, we'll terminate on reorg.
'plugin': os.path.join(os.getcwd(), 'tests/plugins/zeroconf-selective.py'),
'zeroconf-allow': 'any'}
l1, l2 = node_factory.line_graph(2, fundchannel=False, opts=opts)
l1.fundwallet(10000000)
sync_blockheight(bitcoind, [l1]) # height 102
@ -1264,7 +1266,7 @@ def test_funding_reorg_private(node_factory, bitcoind):
daemon = 'DUALOPEND' if l1.config('experimental-dual-fund') else 'CHANNELD'
wait_for(lambda: only_one(l1.rpc.listpeerchannels()['channels'])['status']
== ['{}_AWAITING_LOCKIN:Funding needs 1 more confirmations to be ready.'.format(daemon)])
== ["{}_AWAITING_LOCKIN:They've confirmed channel ready, we haven't yet.".format(daemon)])
bitcoind.generate_block(1) # height 107
l1.wait_channel_active('106x1x0')
l2.wait_channel_active('106x1x0')
@ -1290,13 +1292,15 @@ def test_funding_reorg_private(node_factory, bitcoind):
@pytest.mark.openchannel('v1')
@pytest.mark.openchannel('v2')
def test_funding_reorg_remote_lags(node_factory, bitcoind):
"""Nodes may disagree about short_channel_id before channel announcement
"""
# may_reconnect so channeld will restart; bad gossip can happen due to reorg
opts = {'funding-confirms': 1, 'may_reconnect': True, 'allow_bad_gossip': True,
'allow_warning': True, 'dev-fast-reconnect': None}
'allow_warning': True, 'dev-fast-reconnect': None,
# if it's not zeroconf, l2 will terminate on reorg.
'plugin': os.path.join(os.getcwd(), 'tests/plugins/zeroconf-selective.py'),
'zeroconf-allow': 'any'}
l1, l2 = node_factory.line_graph(2, fundchannel=False, opts=opts)
l1.fundwallet(10000000)
sync_blockheight(bitcoind, [l1]) # height 102
@ -1317,7 +1321,7 @@ def test_funding_reorg_remote_lags(node_factory, bitcoind):
bitcoind.simple_reorg(103, 1) # heights 103 - 108
# But now it's height 104, we need another block to make it announceable.
bitcoind.generate_block(1)
l1.daemon.wait_for_log(r'Peer transient failure .* short_channel_id changed to 104x1x0 \(was 103x1x0\)')
l1.daemon.wait_for_log(r'Short channel id changed from 103x1x0->104x1x0')
l2.daemon.wait_for_logs([r'Peer transient failure in CHANNELD_NORMAL: channeld sent Bad node_signature*'])
@ -1337,6 +1341,20 @@ def test_funding_reorg_remote_lags(node_factory, bitcoind):
l2.daemon.wait_for_log(r'Deleting channel')
@pytest.mark.openchannel('v1')
@pytest.mark.openchannel('v2')
def test_funding_reorg_get_upset(node_factory, bitcoind):
l1, l2 = node_factory.line_graph(2, opts=[{}, {'allow_broken_log': True}])
bitcoind.simple_reorg(103, 1)
# l1 is ok, as funder.
l1.daemon.wait_for_log('Funding tx .* reorganized out, but we opened it...')
assert only_one(l1.rpc.listpeerchannels()['channels'])['state'] == 'CHANNELD_NORMAL'
# l2 is upset!
l2.daemon.wait_for_log('Funding transaction has been reorged out in state CHANNELD_NORMAL')
assert only_one(l2.rpc.listpeerchannels()['channels'])['state'] == 'AWAITING_UNILATERAL'
@unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "deletes database, which is assumed sqlite3")
def test_recover(node_factory, bitcoind):
"""Test the recover option

View File

@ -72,12 +72,6 @@ void broadcast_tx_(struct chain_topology *topo UNNEEDED,
bool (*refresh)(struct channel * UNNEEDED, const struct bitcoin_tx ** UNNEEDED, void *) UNNEEDED,
void *cbarg TAKES UNNEEDED)
{ fprintf(stderr, "broadcast_tx_ called!\n"); abort(); }
/* Generated stub for channel_tell_depth */
bool channel_tell_depth(struct lightningd *ld UNNEEDED,
struct channel *channel UNNEEDED,
const struct bitcoin_txid *txid UNNEEDED,
u32 depth UNNEEDED)
{ fprintf(stderr, "channel_tell_depth called!\n"); abort(); }
/* Generated stub for channel_unsaved_close_conn */
void channel_unsaved_close_conn(struct channel *channel UNNEEDED, const char *why UNNEEDED)
{ fprintf(stderr, "channel_unsaved_close_conn called!\n"); abort(); }
@ -89,6 +83,11 @@ void channel_update_reserve(struct channel *channel UNNEEDED,
struct channel_config *their_config UNNEEDED,
struct amount_sat funding_total UNNEEDED)
{ fprintf(stderr, "channel_update_reserve called!\n"); abort(); }
/* Generated stub for channeld_tell_depth */
void channeld_tell_depth(struct channel *channel UNNEEDED,
const struct bitcoin_txid *txid UNNEEDED,
u32 depth UNNEEDED)
{ fprintf(stderr, "channeld_tell_depth called!\n"); abort(); }
/* Generated stub for cmd_id_from_close_command */
const char *cmd_id_from_close_command(const tal_t *ctx UNNEEDED,
struct lightningd *ld UNNEEDED, struct channel *channel UNNEEDED)
@ -147,6 +146,11 @@ void derive_channel_id(struct channel_id *channel_id UNNEEDED,
/* Generated stub for dev_disconnect_permanent */
bool dev_disconnect_permanent(struct lightningd *ld UNNEEDED)
{ fprintf(stderr, "dev_disconnect_permanent called!\n"); abort(); }
/* Generated stub for dualopend_tell_depth */
void dualopend_tell_depth(struct channel *channel UNNEEDED,
const struct bitcoin_txid *txid UNNEEDED,
u32 depth UNNEEDED)
{ fprintf(stderr, "dualopend_tell_depth called!\n"); abort(); }
/* Generated stub for ecdh */
void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED)
{ fprintf(stderr, "ecdh called!\n"); abort(); }
@ -434,6 +438,13 @@ bool json_tok_streq(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
void kill_uncommitted_channel(struct uncommitted_channel *uc UNNEEDED,
const char *why UNNEEDED)
{ fprintf(stderr, "kill_uncommitted_channel called!\n"); abort(); }
/* Generated stub for lockin_complete */
void lockin_complete(struct channel *channel UNNEEDED,
enum channel_state expected_state UNNEEDED)
{ fprintf(stderr, "lockin_complete called!\n"); abort(); }
/* Generated stub for lockin_has_completed */
void lockin_has_completed(struct channel *channel UNNEEDED, bool record_push UNNEEDED)
{ fprintf(stderr, "lockin_has_completed called!\n"); abort(); }
/* Generated stub for logv */
void logv(struct logger *logger UNNEEDED, enum log_level level UNNEEDED, const struct node_id *node_id UNNEEDED,
bool call_notifier UNNEEDED, const char *fmt UNNEEDED, va_list ap UNNEEDED)