lightningd/closing_control.c: move json_close here from peer_control.c

They share some code, but not much: command_find_channel is made
non-static.  Rest is move-only.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2021-09-15 10:29:23 +09:30 committed by Christian Decker
parent f6a7a3f8a8
commit 789b330338
9 changed files with 452 additions and 511 deletions

View File

@ -1,11 +1,15 @@
#include <bitcoin/feerate.h>
#include <bitcoin/script.h>
#include <ccan/mem/mem.h>
#include <channeld/channeld_wiregen.h>
#include <closingd/closingd_wiregen.h>
#include <common/close_tx.h>
#include <common/closing_fee.h>
#include <common/fee_states.h>
#include <common/initial_commit_tx.h>
#include <common/json_helpers.h>
#include <common/per_peer_state.h>
#include <common/shutdown_scriptpubkey.h>
#include <common/utils.h>
#include <errno.h>
#include <gossipd/gossipd_wiregen.h>
@ -14,14 +18,135 @@
#include <lightningd/chaintopology.h>
#include <lightningd/channel.h>
#include <lightningd/closing_control.h>
#include <lightningd/dual_open_control.h>
#include <lightningd/hsm_control.h>
#include <lightningd/lightningd.h>
#include <lightningd/log.h>
#include <lightningd/opening_common.h>
#include <lightningd/options.h>
#include <lightningd/peer_control.h>
#include <lightningd/subd.h>
#include <openingd/dualopend_wiregen.h>
#include <wire/common_wiregen.h>
struct close_command {
/* Inside struct lightningd close_commands. */
struct list_node list;
/* Command structure. This is the parent of the close command. */
struct command *cmd;
/* Channel being closed. */
struct channel *channel;
};
/* Resolve a single close command. */
static void
resolve_one_close_command(struct close_command *cc, bool cooperative)
{
struct json_stream *result = json_stream_success(cc->cmd);
struct bitcoin_txid txid;
bitcoin_txid(cc->channel->last_tx, &txid);
json_add_tx(result, "tx", cc->channel->last_tx);
json_add_txid(result, "txid", &txid);
if (cooperative)
json_add_string(result, "type", "mutual");
else
json_add_string(result, "type", "unilateral");
was_pending(command_success(cc->cmd, result));
}
/* Resolve a close command for a channel that will be closed soon. */
void resolve_close_command(struct lightningd *ld, struct channel *channel,
bool cooperative)
{
struct close_command *cc;
struct close_command *n;
list_for_each_safe(&ld->close_commands, cc, n, list) {
if (cc->channel != channel)
continue;
resolve_one_close_command(cc, cooperative);
}
}
/* Destroy the close command structure in reaction to the
* channel being destroyed. */
static void
destroy_close_command_on_channel_destroy(struct channel *_ UNUSED,
struct close_command *cc)
{
/* The cc has the command as parent, so resolving the
* command destroys the cc and triggers destroy_close_command.
* Clear the cc->channel first so that we will not try to
* remove a destructor. */
cc->channel = NULL;
was_pending(command_fail(cc->cmd, LIGHTNINGD,
"Channel forgotten before proper close."));
}
/* Destroy the close command structure. */
static void
destroy_close_command(struct close_command *cc)
{
list_del(&cc->list);
/* If destroy_close_command_on_channel_destroy was
* triggered beforehand, it will have cleared
* the channel field, preventing us from removing it
* from an already-destroyed channel. */
if (!cc->channel)
return;
tal_del_destructor2(cc->channel,
&destroy_close_command_on_channel_destroy,
cc);
}
/* Handle timeout. */
static void
close_command_timeout(struct close_command *cc)
{
/* This will trigger drop_to_chain, which will trigger
* resolution of the command and destruction of the
* close_command. */
json_notify_fmt(cc->cmd, LOG_INFORM,
"Timed out, forcing close.");
channel_fail_permanent(cc->channel, REASON_USER,
"Forcibly closed by `close` command timeout");
}
/* Construct a close command structure and add to ld. */
static void
register_close_command(struct lightningd *ld,
struct command *cmd,
struct channel *channel,
unsigned int timeout)
{
struct close_command *cc;
assert(channel);
cc = tal(cmd, struct close_command);
list_add_tail(&ld->close_commands, &cc->list);
cc->cmd = cmd;
cc->channel = channel;
tal_add_destructor(cc, &destroy_close_command);
tal_add_destructor2(channel,
&destroy_close_command_on_channel_destroy,
cc);
if (!channel->owner) {
char *msg = tal_strdup(tmpctx, "peer is offline, will negotiate once they reconnect");
if (timeout)
tal_append_fmt(&msg, " (%u seconds before unilateral close)",
timeout);
json_notify_fmt(cmd, LOG_INFORM, "%s.", msg);
}
log_debug(ld->log, "close_command: timeout = %u", timeout);
if (timeout)
new_reltimer(ld->timers, cc, time_from_sec(timeout),
&close_command_timeout, cc);
}
static struct amount_sat calc_tx_fee(struct amount_sat sat_in,
const struct bitcoin_tx *tx)
{
@ -332,3 +457,304 @@ void peer_start_closingd(struct channel *channel,
take(towire_gossipd_local_channel_close(
tmpctx, channel->scid)));
}
static struct command_result *param_outpoint(struct command *cmd,
const char *name,
const char *buffer,
const jsmntok_t *tok,
struct bitcoin_outpoint **outp)
{
*outp = tal(cmd, struct bitcoin_outpoint);
if (json_to_outpoint(buffer, tok, *outp))
return NULL;
return command_fail_badparam(cmd, name, buffer, tok,
"should be a txid:outnum");
}
static struct command_result *param_feerate_range(struct command *cmd,
const char *name,
const char *buffer,
const jsmntok_t *tok,
u32 **feerate_range)
{
struct command_result *ret;
u32 *rate;
*feerate_range = tal_arr(cmd, u32, 2);
if (tok->type != JSMN_ARRAY || tok->size != 2)
return command_fail_badparam(cmd, name, buffer, tok,
"should be an array of 2 entries");
ret = param_feerate(cmd, name, buffer, tok+1, &rate);
if (ret)
return ret;
(*feerate_range)[0] = *rate;
ret = param_feerate(cmd, name, buffer, tok+2, &rate);
if (ret)
return ret;
(*feerate_range)[1] = *rate;
return NULL;
}
static struct command_result *json_close(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
const jsmntok_t *idtok;
struct peer *peer;
struct channel *channel;
unsigned int *timeout;
const u8 *close_to_script = NULL;
bool close_script_set, wrong_funding_changed, *force_lease_close;
const char *fee_negotiation_step_str;
struct bitcoin_outpoint *wrong_funding;
u32 *feerate_range;
char* end;
bool anysegwit;
if (!param(cmd, buffer, params,
p_req("id", param_tok, &idtok),
p_opt_def("unilateraltimeout", param_number, &timeout,
48 * 3600),
p_opt("destination", param_bitcoin_address, &close_to_script),
p_opt("fee_negotiation_step", param_string,
&fee_negotiation_step_str),
p_opt("wrong_funding", param_outpoint, &wrong_funding),
p_opt_def("force_lease_closed", param_bool,
&force_lease_close, false),
p_opt("feerange", param_feerate_range, &feerate_range),
NULL))
return command_param_failed();
peer = peer_from_json(cmd->ld, buffer, idtok);
if (peer)
channel = peer_active_channel(peer);
else {
struct command_result *res;
res = command_find_channel(cmd, buffer, idtok, &channel);
if (res)
return res;
}
if (!channel && peer) {
struct uncommitted_channel *uc = peer->uncommitted_channel;
if (uc) {
/* Easy case: peer can simply be forgotten. */
kill_uncommitted_channel(uc, "close command called");
goto discard_unopened;
}
if ((channel = peer_unsaved_channel(peer))) {
channel_unsaved_close_conn(channel,
"close command called");
goto discard_unopened;
}
return command_fail(cmd, LIGHTNINGD,
"Peer has no active channel");
}
if (!*force_lease_close && channel->opener != LOCAL
&& get_block_height(cmd->ld->topology) < channel->lease_expiry)
return command_fail(cmd, LIGHTNINGD,
"Peer leased this channel from us, we"
" shouldn't close until lease has expired"
" (lease expires block %u,"
" current block %u)",
channel->lease_expiry,
get_block_height(cmd->ld->topology));
/* If we've set a local shutdown script for this peer, and it's not the
* default upfront script, try to close to a different channel.
* Error is an operator error */
if (close_to_script && channel->shutdown_scriptpubkey[LOCAL]
&& !memeq(close_to_script,
tal_count(close_to_script),
channel->shutdown_scriptpubkey[LOCAL],
tal_count(channel->shutdown_scriptpubkey[LOCAL]))) {
u8 *default_close_to = p2wpkh_for_keyidx(tmpctx, cmd->ld,
channel->final_key_idx);
if (!memeq(default_close_to, tal_count(default_close_to),
channel->shutdown_scriptpubkey[LOCAL],
tal_count(channel->shutdown_scriptpubkey[LOCAL]))) {
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Destination address %s does not match "
"previous shutdown script %s",
tal_hex(tmpctx, channel->shutdown_scriptpubkey[LOCAL]),
tal_hex(tmpctx, close_to_script));
} else {
channel->shutdown_scriptpubkey[LOCAL] =
tal_free(channel->shutdown_scriptpubkey[LOCAL]);
channel->shutdown_scriptpubkey[LOCAL] =
tal_steal(channel, close_to_script);
close_script_set = true;
}
} else if (close_to_script && !channel->shutdown_scriptpubkey[LOCAL]) {
channel->shutdown_scriptpubkey[LOCAL]
= tal_steal(channel, cast_const(u8 *, close_to_script));
close_script_set = true;
} else if (!channel->shutdown_scriptpubkey[LOCAL]) {
channel->shutdown_scriptpubkey[LOCAL]
= p2wpkh_for_keyidx(channel, cmd->ld, channel->final_key_idx);
/* We don't save the default to disk */
close_script_set = false;
} else
close_script_set = false;
/* Don't send a scriptpubkey peer won't accept */
anysegwit = feature_negotiated(cmd->ld->our_features,
channel->peer->their_features,
OPT_SHUTDOWN_ANYSEGWIT);
if (!valid_shutdown_scriptpubkey(channel->shutdown_scriptpubkey[LOCAL],
anysegwit)) {
/* Explicit check for future segwits. */
if (!anysegwit &&
valid_shutdown_scriptpubkey(channel->shutdown_scriptpubkey
[LOCAL], true)) {
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Peer does not allow v1+ shutdown addresses");
}
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Invalid close destination");
}
if (fee_negotiation_step_str == NULL) {
channel->closing_fee_negotiation_step = 50;
channel->closing_fee_negotiation_step_unit =
CLOSING_FEE_NEGOTIATION_STEP_UNIT_PERCENTAGE;
} else {
channel->closing_fee_negotiation_step =
strtoull(fee_negotiation_step_str, &end, 10);
if (channel->closing_fee_negotiation_step == 0)
return command_fail(
cmd, JSONRPC2_INVALID_PARAMS,
"Wrong value given for fee_negotiation_step: "
"\"%s\", must be positive",
fee_negotiation_step_str);
else if (*end == '%') {
if (channel->closing_fee_negotiation_step > 100)
return command_fail(
cmd, JSONRPC2_INVALID_PARAMS,
"Wrong value given for "
"fee_negotiation_step: \"%s\", the "
"percentage should be between 1 and 100",
fee_negotiation_step_str);
channel->closing_fee_negotiation_step_unit =
CLOSING_FEE_NEGOTIATION_STEP_UNIT_PERCENTAGE;
} else if (*end == '\0')
channel->closing_fee_negotiation_step_unit =
CLOSING_FEE_NEGOTIATION_STEP_UNIT_SATOSHI;
else
return command_fail(
cmd, JSONRPC2_INVALID_PARAMS,
"Wrong value given for fee_negotiation_step: "
"\"%s\", should be an integer or an integer "
"followed by %%",
fee_negotiation_step_str);
}
if (wrong_funding) {
if (!feature_negotiated(cmd->ld->our_features,
channel->peer->their_features,
OPT_SHUTDOWN_WRONG_FUNDING)) {
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"wrong_funding feature not negotiated"
" (we said %s, they said %s: try experimental-shutdown-wrong-funding?)",
feature_offered(cmd->ld->our_features
->bits[INIT_FEATURE],
OPT_SHUTDOWN_WRONG_FUNDING)
? "yes" : "no",
feature_offered(channel->peer->their_features,
OPT_SHUTDOWN_WRONG_FUNDING)
? "yes" : "no");
}
wrong_funding_changed = true;
channel->shutdown_wrong_funding
= tal_steal(channel, wrong_funding);
} else {
if (channel->shutdown_wrong_funding) {
channel->shutdown_wrong_funding
= tal_free(channel->shutdown_wrong_funding);
wrong_funding_changed = true;
} else
wrong_funding_changed = false;
}
/* May already be set by previous close cmd. */
tal_free(channel->closing_feerate_range);
/* Works fine if feerate_range is NULL */
channel->closing_feerate_range = tal_steal(channel, feerate_range);
/* Normal case.
* We allow states shutting down and sigexchange; a previous
* close command may have timed out, and this current command
* will continue waiting for the effects of the previous
* close command. */
/* If normal or locking in, transition to shutting down
* state.
* (if already shutting down or sigexchange, just keep
* waiting) */
switch (channel->state) {
case CHANNELD_NORMAL:
case CHANNELD_AWAITING_LOCKIN:
case DUALOPEND_AWAITING_LOCKIN:
channel_set_state(channel,
channel->state, CHANNELD_SHUTTING_DOWN,
REASON_USER,
"User or plugin invoked close command");
/* fallthrough */
case CHANNELD_SHUTTING_DOWN:
if (channel->owner) {
u8 *msg;
if (streq(channel->owner->name, "dualopend")) {
msg = towire_dualopend_send_shutdown(
NULL,
channel->shutdown_scriptpubkey[LOCAL]);
} else
msg = towire_channeld_send_shutdown(
NULL,
channel->shutdown_scriptpubkey[LOCAL],
channel->shutdown_wrong_funding);
subd_send_msg(channel->owner, take(msg));
}
break;
case CLOSINGD_SIGEXCHANGE:
break;
default:
return command_fail(cmd, LIGHTNINGD, "Channel is in state %s",
channel_state_name(channel));
}
/* Register this command for later handling. */
register_close_command(cmd->ld, cmd, channel, *timeout);
/* If we set `channel->shutdown_scriptpubkey[LOCAL]` or
* changed shutdown_wrong_funding, save it. */
if (close_script_set || wrong_funding_changed)
wallet_channel_save(cmd->ld->wallet, channel);
/* Wait until close drops down to chain. */
return command_still_pending(cmd);
discard_unopened: {
struct json_stream *result = json_stream_success(cmd);
json_add_string(result, "type", "unopened");
return command_success(cmd, result);
}
}
static const struct json_command close_command = {
"close",
"channels",
json_close,
"Close the channel with {id} "
"(either peer ID, channel ID, or short channel ID). "
"Force a unilateral close after {unilateraltimeout} seconds (default 48h). "
"If {destination} address is provided, will be used as output address."
};
AUTODATA(json_command, &close_command);

View File

@ -2,10 +2,15 @@
#define LIGHTNING_LIGHTNINGD_CLOSING_CONTROL_H
#include "config.h"
#include <ccan/short_types/short_types.h>
#include <stdbool.h>
struct channel;
struct lightningd;
struct per_peer_state;
void resolve_close_command(struct lightningd *ld, struct channel *channel,
bool cooperative);
void peer_start_closingd(struct channel *channel,
struct per_peer_state *pps);

View File

@ -57,7 +57,6 @@
#include <lightningd/peer_htlcs.h>
#include <lightningd/plugin_hook.h>
#include <limits.h>
#include <openingd/dualopend_wiregen.h>
#include <stdlib.h>
#include <unistd.h>
#include <wally_bip32.h>
@ -65,15 +64,6 @@
#include <wire/onion_wire.h>
#include <wire/wire_sync.h>
struct close_command {
/* Inside struct lightningd close_commands. */
struct list_node list;
/* Command structure. This is the parent of the close command. */
struct command *cmd;
/* Channel being closed. */
struct channel *channel;
};
static void destroy_peer(struct peer *peer)
{
list_del_from(&peer->ld->peers, &peer->list);
@ -218,116 +208,6 @@ static void remove_sig(struct bitcoin_tx *signed_tx)
bitcoin_tx_input_set_witness(signed_tx, 0, NULL);
}
/* Resolve a single close command. */
static void
resolve_one_close_command(struct close_command *cc, bool cooperative)
{
struct json_stream *result = json_stream_success(cc->cmd);
struct bitcoin_txid txid;
bitcoin_txid(cc->channel->last_tx, &txid);
json_add_tx(result, "tx", cc->channel->last_tx);
json_add_txid(result, "txid", &txid);
if (cooperative)
json_add_string(result, "type", "mutual");
else
json_add_string(result, "type", "unilateral");
was_pending(command_success(cc->cmd, result));
}
/* Resolve a close command for a channel that will be closed soon. */
static void
resolve_close_command(struct lightningd *ld, struct channel *channel,
bool cooperative)
{
struct close_command *cc;
struct close_command *n;
list_for_each_safe (&ld->close_commands, cc, n, list) {
if (cc->channel != channel)
continue;
resolve_one_close_command(cc, cooperative);
}
}
/* Destroy the close command structure in reaction to the
* channel being destroyed. */
static void
destroy_close_command_on_channel_destroy(struct channel *_ UNUSED,
struct close_command *cc)
{
/* The cc has the command as parent, so resolving the
* command destroys the cc and triggers destroy_close_command.
* Clear the cc->channel first so that we will not try to
* remove a destructor. */
cc->channel = NULL;
was_pending(command_fail(cc->cmd, LIGHTNINGD,
"Channel forgotten before proper close."));
}
/* Destroy the close command structure. */
static void
destroy_close_command(struct close_command *cc)
{
list_del(&cc->list);
/* If destroy_close_command_on_channel_destroy was
* triggered beforehand, it will have cleared
* the channel field, preventing us from removing it
* from an already-destroyed channel. */
if (!cc->channel)
return;
tal_del_destructor2(cc->channel,
&destroy_close_command_on_channel_destroy,
cc);
}
/* Handle timeout. */
static void
close_command_timeout(struct close_command *cc)
{
/* This will trigger drop_to_chain, which will trigger
* resolution of the command and destruction of the
* close_command. */
json_notify_fmt(cc->cmd, LOG_INFORM,
"Timed out, forcing close.");
channel_fail_permanent(cc->channel, REASON_USER,
"Forcibly closed by `close` command timeout");
}
/* Construct a close command structure and add to ld. */
static void
register_close_command(struct lightningd *ld,
struct command *cmd,
struct channel *channel,
unsigned int timeout)
{
struct close_command *cc;
assert(channel);
cc = tal(cmd, struct close_command);
list_add_tail(&ld->close_commands, &cc->list);
cc->cmd = cmd;
cc->channel = channel;
tal_add_destructor(cc, &destroy_close_command);
tal_add_destructor2(channel,
&destroy_close_command_on_channel_destroy,
cc);
if (!channel->owner) {
char *msg = tal_strdup(tmpctx, "peer is offline, will negotiate once they reconnect");
if (timeout)
tal_append_fmt(&msg, " (%u seconds before unilateral close)",
timeout);
json_notify_fmt(cmd, LOG_INFORM, "%s.", msg);
}
log_debug(ld->log, "close_command: timeout = %u", timeout);
if (timeout)
new_reltimer(ld->timers, cc, time_from_sec(timeout),
&close_command_timeout, cc);
}
static bool invalid_last_tx(const struct bitcoin_tx *tx)
{
/* This problem goes back further, but was discovered just before the
@ -1610,7 +1490,7 @@ static const struct json_command listpeers_command = {
/* Comment added to satisfice AUTODATA */
AUTODATA(json_command, &listpeers_command);
static struct command_result *
struct command_result *
command_find_channel(struct command *cmd,
const char *buffer, const jsmntok_t *tok,
struct channel **channel)
@ -1647,307 +1527,6 @@ command_find_channel(struct command *cmd,
}
}
static struct command_result *param_outpoint(struct command *cmd,
const char *name,
const char *buffer,
const jsmntok_t *tok,
struct bitcoin_outpoint **outp)
{
*outp = tal(cmd, struct bitcoin_outpoint);
if (json_to_outpoint(buffer, tok, *outp))
return NULL;
return command_fail_badparam(cmd, name, buffer, tok,
"should be a txid:outnum");
}
static struct command_result *param_feerate_range(struct command *cmd,
const char *name,
const char *buffer,
const jsmntok_t *tok,
u32 **feerate_range)
{
struct command_result *ret;
u32 *rate;
*feerate_range = tal_arr(cmd, u32, 2);
if (tok->type != JSMN_ARRAY || tok->size != 2)
return command_fail_badparam(cmd, name, buffer, tok,
"should be an array of 2 entries");
ret = param_feerate(cmd, name, buffer, tok+1, &rate);
if (ret)
return ret;
(*feerate_range)[0] = *rate;
ret = param_feerate(cmd, name, buffer, tok+2, &rate);
if (ret)
return ret;
(*feerate_range)[1] = *rate;
return NULL;
}
static struct command_result *json_close(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
const jsmntok_t *idtok;
struct peer *peer;
struct channel *channel COMPILER_WANTS_INIT("gcc 7.3.0 fails, 8.3 OK");
unsigned int *timeout;
const u8 *close_to_script = NULL;
bool close_script_set, wrong_funding_changed, *force_lease_close;
const char *fee_negotiation_step_str;
struct bitcoin_outpoint *wrong_funding;
u32 *feerate_range;
char* end;
bool anysegwit;
if (!param(cmd, buffer, params,
p_req("id", param_tok, &idtok),
p_opt_def("unilateraltimeout", param_number, &timeout,
48 * 3600),
p_opt("destination", param_bitcoin_address, &close_to_script),
p_opt("fee_negotiation_step", param_string,
&fee_negotiation_step_str),
p_opt("wrong_funding", param_outpoint, &wrong_funding),
p_opt_def("force_lease_closed", param_bool,
&force_lease_close, false),
p_opt("feerange", param_feerate_range, &feerate_range),
NULL))
return command_param_failed();
peer = peer_from_json(cmd->ld, buffer, idtok);
if (peer)
channel = peer_active_channel(peer);
else {
struct command_result *res;
res = command_find_channel(cmd, buffer, idtok, &channel);
if (res)
return res;
}
if (!channel && peer) {
struct uncommitted_channel *uc = peer->uncommitted_channel;
if (uc) {
/* Easy case: peer can simply be forgotten. */
kill_uncommitted_channel(uc, "close command called");
goto discard_unopened;
}
if ((channel = peer_unsaved_channel(peer))) {
channel_unsaved_close_conn(channel,
"close command called");
goto discard_unopened;
}
return command_fail(cmd, LIGHTNINGD,
"Peer has no active channel");
}
if (!*force_lease_close && channel->opener != LOCAL
&& get_block_height(cmd->ld->topology) < channel->lease_expiry)
return command_fail(cmd, LIGHTNINGD,
"Peer leased this channel from us, we"
" shouldn't close until lease has expired"
" (lease expires block %u,"
" current block %u)",
channel->lease_expiry,
get_block_height(cmd->ld->topology));
/* If we've set a local shutdown script for this peer, and it's not the
* default upfront script, try to close to a different channel.
* Error is an operator error */
if (close_to_script && channel->shutdown_scriptpubkey[LOCAL]
&& !memeq(close_to_script,
tal_count(close_to_script),
channel->shutdown_scriptpubkey[LOCAL],
tal_count(channel->shutdown_scriptpubkey[LOCAL]))) {
u8 *default_close_to = p2wpkh_for_keyidx(tmpctx, cmd->ld,
channel->final_key_idx);
if (!memeq(default_close_to, tal_count(default_close_to),
channel->shutdown_scriptpubkey[LOCAL],
tal_count(channel->shutdown_scriptpubkey[LOCAL]))) {
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Destination address %s does not match "
"previous shutdown script %s",
tal_hex(tmpctx, channel->shutdown_scriptpubkey[LOCAL]),
tal_hex(tmpctx, close_to_script));
} else {
channel->shutdown_scriptpubkey[LOCAL] =
tal_free(channel->shutdown_scriptpubkey[LOCAL]);
channel->shutdown_scriptpubkey[LOCAL] =
tal_steal(channel, close_to_script);
close_script_set = true;
}
} else if (close_to_script && !channel->shutdown_scriptpubkey[LOCAL]) {
channel->shutdown_scriptpubkey[LOCAL]
= tal_steal(channel, cast_const(u8 *, close_to_script));
close_script_set = true;
} else if (!channel->shutdown_scriptpubkey[LOCAL]) {
channel->shutdown_scriptpubkey[LOCAL]
= p2wpkh_for_keyidx(channel, cmd->ld, channel->final_key_idx);
/* We don't save the default to disk */
close_script_set = false;
} else
close_script_set = false;
/* Don't send a scriptpubkey peer won't accept */
anysegwit = feature_negotiated(cmd->ld->our_features,
channel->peer->their_features,
OPT_SHUTDOWN_ANYSEGWIT);
if (!valid_shutdown_scriptpubkey(channel->shutdown_scriptpubkey[LOCAL],
anysegwit)) {
/* Explicit check for future segwits. */
if (!anysegwit &&
valid_shutdown_scriptpubkey(channel->shutdown_scriptpubkey
[LOCAL], true)) {
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Peer does not allow v1+ shutdown addresses");
}
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Invalid close destination");
}
if (fee_negotiation_step_str == NULL) {
channel->closing_fee_negotiation_step = 50;
channel->closing_fee_negotiation_step_unit =
CLOSING_FEE_NEGOTIATION_STEP_UNIT_PERCENTAGE;
} else {
channel->closing_fee_negotiation_step =
strtoull(fee_negotiation_step_str, &end, 10);
if (channel->closing_fee_negotiation_step == 0)
return command_fail(
cmd, JSONRPC2_INVALID_PARAMS,
"Wrong value given for fee_negotiation_step: "
"\"%s\", must be positive",
fee_negotiation_step_str);
else if (*end == '%') {
if (channel->closing_fee_negotiation_step > 100)
return command_fail(
cmd, JSONRPC2_INVALID_PARAMS,
"Wrong value given for "
"fee_negotiation_step: \"%s\", the "
"percentage should be between 1 and 100",
fee_negotiation_step_str);
channel->closing_fee_negotiation_step_unit =
CLOSING_FEE_NEGOTIATION_STEP_UNIT_PERCENTAGE;
} else if (*end == '\0')
channel->closing_fee_negotiation_step_unit =
CLOSING_FEE_NEGOTIATION_STEP_UNIT_SATOSHI;
else
return command_fail(
cmd, JSONRPC2_INVALID_PARAMS,
"Wrong value given for fee_negotiation_step: "
"\"%s\", should be an integer or an integer "
"followed by %%",
fee_negotiation_step_str);
}
if (wrong_funding) {
if (!feature_negotiated(cmd->ld->our_features,
channel->peer->their_features,
OPT_SHUTDOWN_WRONG_FUNDING)) {
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"wrong_funding feature not negotiated"
" (we said %s, they said %s: try experimental-shutdown-wrong-funding?)",
feature_offered(cmd->ld->our_features
->bits[INIT_FEATURE],
OPT_SHUTDOWN_WRONG_FUNDING)
? "yes" : "no",
feature_offered(channel->peer->their_features,
OPT_SHUTDOWN_WRONG_FUNDING)
? "yes" : "no");
}
wrong_funding_changed = true;
channel->shutdown_wrong_funding
= tal_steal(channel, wrong_funding);
} else {
if (channel->shutdown_wrong_funding) {
channel->shutdown_wrong_funding
= tal_free(channel->shutdown_wrong_funding);
wrong_funding_changed = true;
} else
wrong_funding_changed = false;
}
/* May already be set by previous close cmd. */
tal_free(channel->closing_feerate_range);
/* Works fine if feerate_range is NULL */
channel->closing_feerate_range = tal_steal(channel, feerate_range);
/* Normal case.
* We allow states shutting down and sigexchange; a previous
* close command may have timed out, and this current command
* will continue waiting for the effects of the previous
* close command. */
/* If normal or locking in, transition to shutting down
* state.
* (if already shutting down or sigexchange, just keep
* waiting) */
switch (channel->state) {
case CHANNELD_NORMAL:
case CHANNELD_AWAITING_LOCKIN:
case DUALOPEND_AWAITING_LOCKIN:
channel_set_state(channel,
channel->state, CHANNELD_SHUTTING_DOWN,
REASON_USER,
"User or plugin invoked close command");
/* fallthrough */
case CHANNELD_SHUTTING_DOWN:
if (channel->owner) {
u8 *msg;
if (streq(channel->owner->name, "dualopend")) {
msg = towire_dualopend_send_shutdown(
NULL,
channel->shutdown_scriptpubkey[LOCAL]);
} else
msg = towire_channeld_send_shutdown(
NULL,
channel->shutdown_scriptpubkey[LOCAL],
channel->shutdown_wrong_funding);
subd_send_msg(channel->owner, take(msg));
}
break;
case CLOSINGD_SIGEXCHANGE:
break;
default:
return command_fail(cmd, LIGHTNINGD, "Channel is in state %s",
channel_state_name(channel));
}
/* Register this command for later handling. */
register_close_command(cmd->ld, cmd, channel, *timeout);
/* If we set `channel->shutdown_scriptpubkey[LOCAL]` or
* changed shutdown_wrong_funding, save it. */
if (close_script_set || wrong_funding_changed)
wallet_channel_save(cmd->ld->wallet, channel);
/* Wait until close drops down to chain. */
return command_still_pending(cmd);
discard_unopened: {
struct json_stream *result = json_stream_success(cmd);
json_add_string(result, "type", "unopened");
return command_success(cmd, result);
}
}
static const struct json_command close_command = {
"close",
"channels",
json_close,
"Close the channel with {id} "
"(either peer ID, channel ID, or short channel ID). "
"Force a unilateral close after {unilateraltimeout} seconds (default 48h). "
"If {destination} address is provided, will be used as output address."
};
AUTODATA(json_command, &close_command);
static void activate_peer(struct peer *peer, u32 delay)
{
u8 *msg;

View File

@ -109,4 +109,11 @@ void handle_custommsg_in(struct lightningd *ld, const struct node_id *peer_id,
void waitblockheight_notify_new_block(struct lightningd *ld,
u32 block_height);
/* JSON parameter by channel_id or scid */
struct command_result *
command_find_channel(struct command *cmd,
const char *buffer, const jsmntok_t *tok,
struct channel **channel);
#endif /* LIGHTNING_LIGHTNINGD_PEER_CONTROL_H */

View File

@ -102,13 +102,6 @@ void channel_set_last_tx(struct channel *channel UNNEEDED,
const struct bitcoin_signature *sig UNNEEDED,
enum wallet_tx_type type UNNEEDED)
{ fprintf(stderr, "channel_set_last_tx called!\n"); abort(); }
/* Generated stub for channel_set_state */
void channel_set_state(struct channel *channel UNNEEDED,
enum channel_state old_state UNNEEDED,
enum channel_state state UNNEEDED,
enum state_change reason UNNEEDED,
char *why UNNEEDED)
{ fprintf(stderr, "channel_set_state called!\n"); abort(); }
/* Generated stub for channel_state_name */
const char *channel_state_name(const struct channel *channel UNNEEDED)
{ fprintf(stderr, "channel_state_name called!\n"); abort(); }
@ -197,9 +190,6 @@ bool feature_is_set(const u8 *features UNNEEDED, size_t bit UNNEEDED)
bool feature_negotiated(const struct feature_set *our_features UNNEEDED,
const u8 *their_features UNNEEDED, size_t f UNNEEDED)
{ fprintf(stderr, "feature_negotiated called!\n"); abort(); }
/* Generated stub for feature_offered */
bool feature_offered(const u8 *features UNNEEDED, size_t f UNNEEDED)
{ fprintf(stderr, "feature_offered called!\n"); abort(); }
/* Generated stub for find_plugin_for_command */
struct plugin *find_plugin_for_command(struct lightningd *ld UNNEEDED,
const char *cmd_name UNNEEDED)
@ -378,12 +368,6 @@ void json_array_start(struct json_stream *js UNNEEDED, const char *fieldname UNN
char *json_member_direct(struct json_stream *js UNNEEDED,
const char *fieldname UNNEEDED, size_t extra UNNEEDED)
{ fprintf(stderr, "json_member_direct called!\n"); abort(); }
/* Generated stub for json_notify_fmt */
void json_notify_fmt(struct command *cmd UNNEEDED,
enum log_level level UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "json_notify_fmt called!\n"); abort(); }
/* Generated stub for json_object_end */
void json_object_end(struct json_stream *js UNNEEDED)
{ fprintf(stderr, "json_object_end called!\n"); abort(); }
@ -412,10 +396,6 @@ bool json_to_msat(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
bool json_to_node_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
struct node_id *id UNNEEDED)
{ fprintf(stderr, "json_to_node_id called!\n"); abort(); }
/* Generated stub for json_to_outpoint */
bool json_to_outpoint(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
struct bitcoin_outpoint *op UNNEEDED)
{ fprintf(stderr, "json_to_outpoint called!\n"); abort(); }
/* Generated stub for json_to_short_channel_id */
bool json_to_short_channel_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
struct short_channel_id *scid UNNEEDED)
@ -511,13 +491,6 @@ struct command_result *param_bin_from_hex(struct command *cmd UNNEEDED, const ch
const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
u8 **bin UNNEEDED)
{ fprintf(stderr, "param_bin_from_hex called!\n"); abort(); }
/* Generated stub for param_bitcoin_address */
struct command_result *param_bitcoin_address(struct command *cmd UNNEEDED,
const char *name UNNEEDED,
const char *buffer UNNEEDED,
const jsmntok_t *tok UNNEEDED,
const u8 **scriptpubkey UNNEEDED)
{ fprintf(stderr, "param_bitcoin_address called!\n"); abort(); }
/* Generated stub for param_bool */
struct command_result *param_bool(struct command *cmd UNNEEDED, const char *name UNNEEDED,
const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
@ -537,11 +510,6 @@ struct command_result *param_escaped_string(struct command *cmd UNNEEDED,
const jsmntok_t *tok UNNEEDED,
const char **str UNNEEDED)
{ fprintf(stderr, "param_escaped_string called!\n"); abort(); }
/* Generated stub for param_feerate */
struct command_result *param_feerate(struct command *cmd UNNEEDED, const char *name UNNEEDED,
const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
u32 **feerate UNNEEDED)
{ fprintf(stderr, "param_feerate called!\n"); abort(); }
/* Generated stub for param_label */
struct command_result *param_label(struct command *cmd UNNEEDED, const char *name UNNEEDED,
const char * buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
@ -588,11 +556,6 @@ struct command_result *param_string(struct command *cmd UNNEEDED, const char *na
const char * buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
const char **str UNNEEDED)
{ fprintf(stderr, "param_string called!\n"); abort(); }
/* Generated stub for param_tok */
struct command_result *param_tok(struct command *cmd UNNEEDED, const char *name UNNEEDED,
const char *buffer UNNEEDED, const jsmntok_t * tok UNNEEDED,
const jsmntok_t **out UNNEEDED)
{ fprintf(stderr, "param_tok called!\n"); abort(); }
/* Generated stub for param_u64 */
struct command_result *param_u64(struct command *cmd UNNEEDED, const char *name UNNEEDED,
const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
@ -644,6 +607,10 @@ bool plugin_hook_call_(struct lightningd *ld UNNEEDED, const struct plugin_hook
void plugin_request_send(struct plugin *plugin UNNEEDED,
struct jsonrpc_request *req TAKES UNNEEDED)
{ fprintf(stderr, "plugin_request_send called!\n"); abort(); }
/* Generated stub for resolve_close_command */
void resolve_close_command(struct lightningd *ld UNNEEDED, struct channel *channel UNNEEDED,
bool cooperative UNNEEDED)
{ fprintf(stderr, "resolve_close_command called!\n"); abort(); }
/* Generated stub for subd_req_ */
void subd_req_(const tal_t *ctx UNNEEDED,
struct subd *sd UNNEEDED,
@ -670,9 +637,6 @@ u8 *towire_channeld_dev_memleak(const tal_t *ctx UNNEEDED)
/* Generated stub for towire_channeld_dev_reenable_commit */
u8 *towire_channeld_dev_reenable_commit(const tal_t *ctx UNNEEDED)
{ fprintf(stderr, "towire_channeld_dev_reenable_commit called!\n"); abort(); }
/* Generated stub for towire_channeld_send_shutdown */
u8 *towire_channeld_send_shutdown(const tal_t *ctx UNNEEDED, const u8 *shutdown_scriptpubkey UNNEEDED, const struct bitcoin_outpoint *wrong_funding UNNEEDED)
{ fprintf(stderr, "towire_channeld_send_shutdown called!\n"); abort(); }
/* Generated stub for towire_channeld_specific_feerates */
u8 *towire_channeld_specific_feerates(const tal_t *ctx UNNEEDED, u32 feerate_base UNNEEDED, u32 feerate_ppm UNNEEDED)
{ fprintf(stderr, "towire_channeld_specific_feerates called!\n"); abort(); }
@ -682,9 +646,6 @@ u8 *towire_connectd_connect_to_peer(const tal_t *ctx UNNEEDED, const struct node
/* Generated stub for towire_connectd_peer_final_msg */
u8 *towire_connectd_peer_final_msg(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, const struct per_peer_state *pps UNNEEDED, const u8 *msg UNNEEDED)
{ fprintf(stderr, "towire_connectd_peer_final_msg called!\n"); abort(); }
/* Generated stub for towire_dualopend_send_shutdown */
u8 *towire_dualopend_send_shutdown(const tal_t *ctx UNNEEDED, const u8 *shutdown_scriptpubkey UNNEEDED)
{ fprintf(stderr, "towire_dualopend_send_shutdown called!\n"); abort(); }
/* Generated stub for towire_errorfmt */
u8 *towire_errorfmt(const tal_t *ctx UNNEEDED,
const struct channel_id *channel UNNEEDED,
@ -710,10 +671,6 @@ u8 *towire_warningfmt(const tal_t *ctx UNNEEDED,
const struct channel_id *channel UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "towire_warningfmt called!\n"); abort(); }
/* Generated stub for valid_shutdown_scriptpubkey */
bool valid_shutdown_scriptpubkey(const u8 *scriptpubkey UNNEEDED,
bool anysegwit UNNEEDED)
{ fprintf(stderr, "valid_shutdown_scriptpubkey called!\n"); abort(); }
/* Generated stub for version */
const char *version(void)
{ fprintf(stderr, "version called!\n"); abort(); }

View File

@ -2074,4 +2074,4 @@ struct db_query db_postgres_queries[] = {
#endif /* LIGHTNINGD_WALLET_GEN_DB_POSTGRES */
// SHA256STAMP:a70af01d3b2f3a7003703b7feb0b2ef12359e0d2850bde1697a53780e2f5dbae
// SHA256STAMP:e356b7327b760559f9a7c31a7ea4a09d50194c7aacc6daef6ba9fb5caf43ae83

View File

@ -2074,4 +2074,4 @@ struct db_query db_sqlite3_queries[] = {
#endif /* LIGHTNINGD_WALLET_GEN_DB_SQLITE3 */
// SHA256STAMP:a70af01d3b2f3a7003703b7feb0b2ef12359e0d2850bde1697a53780e2f5dbae
// SHA256STAMP:e356b7327b760559f9a7c31a7ea4a09d50194c7aacc6daef6ba9fb5caf43ae83

View File

@ -1362,11 +1362,11 @@ msgstr ""
msgid "not a valid SQL statement"
msgstr ""
#: wallet/test/run-wallet.c:1541
#: wallet/test/run-wallet.c:1508
msgid "SELECT COUNT(1) FROM channel_funding_inflights WHERE channel_id = ?;"
msgstr ""
#: wallet/test/run-wallet.c:1754
#: wallet/test/run-wallet.c:1721
msgid "INSERT INTO channels (id) VALUES (1);"
msgstr ""
# SHA256STAMP:651a6c15e8780351cd32a4e6dc3011b1c5fc2af6308b0e65a442dda2a3874e19
# SHA256STAMP:0b3b17a4eb95067fdebc9d90c962c46e40fdef2002f92856cc31800ab37fbe59

View File

@ -381,12 +381,6 @@ void json_array_start(struct json_stream *js UNNEEDED, const char *fieldname UNN
const jsmntok_t *json_get_member(const char *buffer UNNEEDED, const jsmntok_t tok[] UNNEEDED,
const char *label UNNEEDED)
{ fprintf(stderr, "json_get_member called!\n"); abort(); }
/* Generated stub for json_notify_fmt */
void json_notify_fmt(struct command *cmd UNNEEDED,
enum log_level level UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "json_notify_fmt called!\n"); abort(); }
/* Generated stub for json_object_end */
void json_object_end(struct json_stream *js UNNEEDED)
{ fprintf(stderr, "json_object_end called!\n"); abort(); }
@ -407,10 +401,6 @@ bool json_to_node_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
bool json_to_number(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
unsigned int *num UNNEEDED)
{ fprintf(stderr, "json_to_number called!\n"); abort(); }
/* Generated stub for json_to_outpoint */
bool json_to_outpoint(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
struct bitcoin_outpoint *op UNNEEDED)
{ fprintf(stderr, "json_to_outpoint called!\n"); abort(); }
/* Generated stub for json_to_preimage */
bool json_to_preimage(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, struct preimage *preimage UNNEEDED)
{ fprintf(stderr, "json_to_preimage called!\n"); abort(); }
@ -549,13 +539,6 @@ struct command_result *param_bin_from_hex(struct command *cmd UNNEEDED, const ch
const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
u8 **bin UNNEEDED)
{ fprintf(stderr, "param_bin_from_hex called!\n"); abort(); }
/* Generated stub for param_bitcoin_address */
struct command_result *param_bitcoin_address(struct command *cmd UNNEEDED,
const char *name UNNEEDED,
const char *buffer UNNEEDED,
const jsmntok_t *tok UNNEEDED,
const u8 **scriptpubkey UNNEEDED)
{ fprintf(stderr, "param_bitcoin_address called!\n"); abort(); }
/* Generated stub for param_bool */
struct command_result *param_bool(struct command *cmd UNNEEDED, const char *name UNNEEDED,
const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
@ -568,11 +551,6 @@ struct command_result *param_channel_id(struct command *cmd UNNEEDED,
const jsmntok_t *tok UNNEEDED,
struct channel_id **cid UNNEEDED)
{ fprintf(stderr, "param_channel_id called!\n"); abort(); }
/* Generated stub for param_feerate */
struct command_result *param_feerate(struct command *cmd UNNEEDED, const char *name UNNEEDED,
const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
u32 **feerate UNNEEDED)
{ fprintf(stderr, "param_feerate called!\n"); abort(); }
/* Generated stub for param_loglevel */
struct command_result *param_loglevel(struct command *cmd UNNEEDED,
const char *name UNNEEDED,
@ -609,11 +587,6 @@ struct command_result *param_string(struct command *cmd UNNEEDED, const char *na
const char * buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
const char **str UNNEEDED)
{ fprintf(stderr, "param_string called!\n"); abort(); }
/* Generated stub for param_tok */
struct command_result *param_tok(struct command *cmd UNNEEDED, const char *name UNNEEDED,
const char *buffer UNNEEDED, const jsmntok_t * tok UNNEEDED,
const jsmntok_t **out UNNEEDED)
{ fprintf(stderr, "param_tok called!\n"); abort(); }
/* Generated stub for parse_onionpacket */
struct onionpacket *parse_onionpacket(const tal_t *ctx UNNEEDED,
const u8 *src UNNEEDED,
@ -680,6 +653,10 @@ struct route_step *process_onionpacket(
bool has_realm
)
{ fprintf(stderr, "process_onionpacket called!\n"); abort(); }
/* Generated stub for resolve_close_command */
void resolve_close_command(struct lightningd *ld UNNEEDED, struct channel *channel UNNEEDED,
bool cooperative UNNEEDED)
{ fprintf(stderr, "resolve_close_command called!\n"); abort(); }
/* Generated stub for serialize_onionpacket */
u8 *serialize_onionpacket(
const tal_t *ctx UNNEEDED,
@ -738,9 +715,6 @@ u8 *towire_channeld_got_revoke_reply(const tal_t *ctx UNNEEDED)
/* Generated stub for towire_channeld_offer_htlc */
u8 *towire_channeld_offer_htlc(const tal_t *ctx UNNEEDED, struct amount_msat amount_msat UNNEEDED, u32 cltv_expiry UNNEEDED, const struct sha256 *payment_hash UNNEEDED, const u8 onion_routing_packet[1366] UNNEEDED, const struct pubkey *blinding UNNEEDED)
{ fprintf(stderr, "towire_channeld_offer_htlc called!\n"); abort(); }
/* Generated stub for towire_channeld_send_shutdown */
u8 *towire_channeld_send_shutdown(const tal_t *ctx UNNEEDED, const u8 *shutdown_scriptpubkey UNNEEDED, const struct bitcoin_outpoint *wrong_funding UNNEEDED)
{ fprintf(stderr, "towire_channeld_send_shutdown called!\n"); abort(); }
/* Generated stub for towire_channeld_sending_commitsig_reply */
u8 *towire_channeld_sending_commitsig_reply(const tal_t *ctx UNNEEDED)
{ fprintf(stderr, "towire_channeld_sending_commitsig_reply called!\n"); abort(); }
@ -759,9 +733,6 @@ u8 *towire_connectd_peer_final_msg(const tal_t *ctx UNNEEDED, const struct node_
/* Generated stub for towire_custommsg_out */
u8 *towire_custommsg_out(const tal_t *ctx UNNEEDED, const u8 *msg UNNEEDED)
{ fprintf(stderr, "towire_custommsg_out called!\n"); abort(); }
/* Generated stub for towire_dualopend_send_shutdown */
u8 *towire_dualopend_send_shutdown(const tal_t *ctx UNNEEDED, const u8 *shutdown_scriptpubkey UNNEEDED)
{ fprintf(stderr, "towire_dualopend_send_shutdown called!\n"); abort(); }
/* Generated stub for towire_errorfmt */
u8 *towire_errorfmt(const tal_t *ctx UNNEEDED,
const struct channel_id *channel UNNEEDED,
@ -835,10 +806,6 @@ u8 *towire_warningfmt(const tal_t *ctx UNNEEDED,
const struct channel_id *channel UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "towire_warningfmt called!\n"); abort(); }
/* Generated stub for valid_shutdown_scriptpubkey */
bool valid_shutdown_scriptpubkey(const u8 *scriptpubkey UNNEEDED,
bool anysegwit UNNEEDED)
{ fprintf(stderr, "valid_shutdown_scriptpubkey called!\n"); abort(); }
/* Generated stub for watch_txid */
struct txwatch *watch_txid(const tal_t *ctx UNNEEDED,
struct chain_topology *topo UNNEEDED,