diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 5ae8add2f..dc74e7eac 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -3107,6 +3107,7 @@ static struct command_result *json_openchannel_init(struct command *cmd, } if (ctype && + !cmd->ld->dev_any_channel_type && !channel_type_accept(tmpctx, ctype->features, cmd->ld->our_features)) { @@ -4042,7 +4043,8 @@ bool peer_start_dualopend(struct peer *peer, &channel->local_basepoints, &channel->local_funding_pubkey, channel->minimum_depth, - peer->ld->config.require_confirmed_inputs); + peer->ld->config.require_confirmed_inputs, + peer->ld->dev_any_channel_type); subd_send_msg(channel->owner, take(msg)); return true; } diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 861fb8c8d..3919c678e 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -144,6 +144,7 @@ static struct lightningd *new_lightningd(const tal_t *ctx) ld->dev_ignore_modern_onion = false; ld->dev_disable_commit = -1; ld->dev_no_ping_timer = false; + ld->dev_any_channel_type = false; /*~ This is a CCAN list: an embedded double-linked list. It's not * really typesafe, but relies on convention to access the contents. diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h index b2de15072..f823f59e7 100644 --- a/lightningd/lightningd.h +++ b/lightningd/lightningd.h @@ -337,6 +337,9 @@ struct lightningd { /* Tell channeld not to worry about pings. */ bool dev_no_ping_timer; + /* Tell openingd/dualopend to accept all, allow sending any. */ + bool dev_any_channel_type; + /* tor support */ struct wireaddr *proxyaddr; bool always_use_proxy; diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index a7fc10eb2..6015ac2c6 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -981,7 +981,8 @@ bool peer_start_openingd(struct peer *peer, struct peer_fd *peer_fd) uc->minimum_depth, minrate, maxrate, peer->ld->dev_force_tmp_channel_id, - peer->ld->config.allowdustreserve); + peer->ld->config.allowdustreserve, + peer->ld->dev_any_channel_type); subd_send_msg(uc->open_daemon, take(msg)); return true; } @@ -1171,6 +1172,7 @@ static struct command_result *json_fundchannel_start(struct command *cmd, return command_param_failed(); if (ctype && + !cmd->ld->dev_any_channel_type && !channel_type_accept(tmpctx, ctype->features, cmd->ld->our_features)) { diff --git a/lightningd/options.c b/lightningd/options.c index 417e801e1..80d110412 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -903,6 +903,10 @@ static void dev_register_opts(struct lightningd *ld) opt_set_bool_arg, opt_show_bool, &ld->config.allowdustreserve, "If true, we allow the `fundchannel` RPC command and the `openchannel` plugin hook to set a reserve that is below the dust limit."); + clnopt_noarg("--dev-any-channel-type", OPT_DEV, + opt_set_bool, + &ld->dev_any_channel_type, + "Allow sending any channel type, and accept any"); } static const struct config testnet_config = { diff --git a/openingd/dualopend.c b/openingd/dualopend.c index ac0bc06f0..6e8d45605 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -226,6 +226,8 @@ struct state { /* Does this negotation require confirmed inputs? */ bool require_confirmed_inputs[NUM_SIDES]; + + bool dev_accept_any_channel_type; }; /* psbt_changeset_get_next - Get next message to send @@ -2424,11 +2426,18 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) open_tlv->channel_type, state->our_features); if (!state->channel_type) { - negotiation_failed(state, - "Did not support channel_type %s", - fmt_featurebits(tmpctx, - open_tlv->channel_type)); - return; + if (state->dev_accept_any_channel_type) { + status_unusual("dev-any-channel-type: accepting %s", + fmt_featurebits(tmpctx, + open_tlv->channel_type)); + state->channel_type = channel_type_from(state, open_tlv->channel_type); + } else { + negotiation_failed(state, + "Did not support channel_type %s", + fmt_featurebits(tmpctx, + open_tlv->channel_type)); + return; + } } } else state->channel_type @@ -4372,7 +4381,8 @@ int main(int argc, char *argv[]) &state->our_points, &state->our_funding_pubkey, &state->minimum_depth, - &state->require_confirmed_inputs[LOCAL])) { + &state->require_confirmed_inputs[LOCAL], + &state->dev_accept_any_channel_type)) { /*~ Initially we're not associated with a channel, but * handle_peer_gossip_or_error compares this. */ memset(&state->channel_id, 0, sizeof(state->channel_id)); diff --git a/openingd/dualopend_wire.csv b/openingd/dualopend_wire.csv index 92775e3ce..06996100f 100644 --- a/openingd/dualopend_wire.csv +++ b/openingd/dualopend_wire.csv @@ -29,6 +29,7 @@ msgdata,dualopend_init,our_funding_pubkey,pubkey, # Constraints in case the other end tries to open a channel. msgdata,dualopend_init,minimum_depth,u32, msgdata,dualopend_init,require_confirmed_inputs,bool, +msgdata,dualopend_init,dev_accept_any_channel_type,bool, # master-dualopend: peer has reconnected msgtype,dualopend_reinit,7001 diff --git a/openingd/openingd.c b/openingd/openingd.c index acba29718..3fd6a91d5 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -103,6 +103,8 @@ struct state { struct amount_sat *reserve; bool allowdustreserve; + + bool dev_accept_any_channel_type; }; /*~ If we can't agree on parameters, we fail to open the channel. @@ -965,11 +967,18 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) state->channel_type = channel_type_accept( state, open_tlvs->channel_type, state->our_features); if (!state->channel_type) { - negotiation_failed(state, - "Did not support channel_type %s", - fmt_featurebits(tmpctx, - open_tlvs->channel_type)); - return NULL; + if (state->dev_accept_any_channel_type) { + status_unusual("dev-any-channel-type: accepting %s", + fmt_featurebits(tmpctx, + open_tlvs->channel_type)); + state->channel_type = channel_type_from(state, open_tlvs->channel_type); + } else { + negotiation_failed(state, + "Did not support channel_type %s", + fmt_featurebits(tmpctx, + open_tlvs->channel_type)); + return NULL; + } } } else { open_channel_had_channel_type = false; @@ -1548,7 +1557,8 @@ int main(int argc, char *argv[]) &state->minimum_depth, &state->min_feerate, &state->max_feerate, &state->dev_force_tmp_channel_id, - &state->allowdustreserve)) + &state->allowdustreserve, + &state->dev_accept_any_channel_type)) master_badmsg(WIRE_OPENINGD_INIT, msg); /* 3 == peer, 4 = hsmd */ diff --git a/openingd/openingd_wire.csv b/openingd/openingd_wire.csv index 1039ef161..65aac949f 100644 --- a/openingd/openingd_wire.csv +++ b/openingd/openingd_wire.csv @@ -28,6 +28,7 @@ msgdata,openingd_init,dev_temporary_channel_id,?byte,32 # reserves? This is explicitly required by the spec for safety # reasons, but some implementations and users keep asking for it. msgdata,openingd_init,allowdustreserve,bool, +msgdata,openingd_init,dev_accept_any_channel_type,bool, # Openingd->master: they offered channel, should we continue? msgtype,openingd_got_offer,6005 diff --git a/tests/test_opening.py b/tests/test_opening.py index bb573147c..7bc4a01fd 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -2636,6 +2636,25 @@ def test_opening_explicit_channel_type(node_factory, bitcoind): with pytest.raises(RpcError, match=r'channel_type not supported'): l1.rpc.openchannel_init(l3.info['id'], FUNDAMOUNT - 1000, psbt, channel_type=[STATIC_REMOTEKEY, ANCHORS_OLD]) + # l1 will try, with dev-any-channel-type, l2 will reject. + l1.stop() + l1.daemon.opts['dev-any-channel-type'] = None + l1.start() + l1.connect(l2) + + with pytest.raises(RpcError, match=r'They sent ERROR .*: You gave bad parameters: Did not support channel_type 12,20'): + l1.rpc.fundchannel_start(l2.info['id'], FUNDAMOUNT, channel_type=[STATIC_REMOTEKEY, ANCHORS_OLD]) + + # Now make l2 accept it! + l2.stop() + l2.daemon.opts['dev-any-channel-type'] = None + l2.start() + l1.connect(l2) + + l1.rpc.fundchannel_start(l2.info['id'], FUNDAMOUNT, channel_type=[STATIC_REMOTEKEY, ANCHORS_OLD]) + # FIXME: Check type is actually correct! + l1.rpc.fundchannel_cancel(l2.info['id']) + l1.rpc.unreserveinputs(psbt) # Works with fundchannel / multifundchannel @@ -2646,5 +2665,6 @@ def test_opening_explicit_channel_type(node_factory, bitcoind): bitcoind.generate_block(1, wait_for_mempool=1) wait_for(lambda: len(l1.rpc.listfunds()['outputs']) == 1) + l1.connect(l3) # FIXME: Check type is actually correct! l1.rpc.fundchannel(l3.info['id'], FUNDAMOUNT // 3, channel_type=[STATIC_REMOTEKEY])