From a5b9fb66a42aa944b32208825841f17cbf06c324 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Mon, 30 May 2022 00:47:43 -0500 Subject: [PATCH] Add option to allow even custom messages to be sent Changelog-Experimental: config: new option --experimental-all-onion-messages, which behaves like --experimental-onion-messages but also allow even-numbered messages to be sent --- connectd/multiplex.c | 1 + doc/lightning-listconfigs.7 | 2 ++ doc/lightning-listconfigs.7.md | 1 + doc/lightning-sendcustommsg.7.md | 5 +-- doc/lightningd-config.5.md | 5 +++ doc/schemas/listconfigs.schema.json | 4 +++ lightningd/connect_control.c | 6 ++-- lightningd/lightningd.h | 3 ++ lightningd/options.c | 16 +++++++++ tests/test_misc.py | 53 +++++++++++++++++++++++++++++ 10 files changed, 92 insertions(+), 4 deletions(-) diff --git a/connectd/multiplex.c b/connectd/multiplex.c index 54740a7b3c4f..20547a4607b9 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -622,6 +622,7 @@ static bool handle_custommsg(struct daemon *daemon, const u8 *msg) { enum peer_wire type = fromwire_peektype(msg); + // fixme use allow_even_custom_message config here if (type % 2 == 1 && !peer_wire_is_defined(type)) { /* The message is not part of the messages we know how to * handle. Assuming this is a custommsg, we just forward it to the diff --git a/doc/lightning-listconfigs.7 b/doc/lightning-listconfigs.7 index 79e81678371f..f00290f23a89 100644 --- a/doc/lightning-listconfigs.7 +++ b/doc/lightning-listconfigs.7 @@ -88,6 +88,8 @@ On success, an object is returned, containing: .IP \[bu] \fBexperimental-onion-messages\fR (boolean, optional): \fBexperimental-onion-messages\fR field from config or cmdline, or default .IP \[bu] +\fBexperimental-all-onion-messages\fR (boolean, optional): \fBexperimental-all-onion-messages\fR field from config or cmdline, or default +.IP \[bu] \fBexperimental-offers\fR (boolean, optional): \fBexperimental-offers\fR field from config or cmdline, or default .IP \[bu] \fBexperimental-shutdown-wrong-funding\fR (boolean, optional): \fBexperimental-shutdown-wrong-funding\fR field from config or cmdline, or default diff --git a/doc/lightning-listconfigs.7.md b/doc/lightning-listconfigs.7.md index 823ee79ba8fe..5cf6f55a1fc5 100644 --- a/doc/lightning-listconfigs.7.md +++ b/doc/lightning-listconfigs.7.md @@ -54,6 +54,7 @@ On success, an object is returned, containing: - **large-channels** (boolean, optional): `large-channels` field from config or cmdline, or default - **experimental-dual-fund** (boolean, optional): `experimental-dual-fund` field from config or cmdline, or default - **experimental-onion-messages** (boolean, optional): `experimental-onion-messages` field from config or cmdline, or default +- **experimental-all-onion-messages** (boolean, optional): `experimental-all-onion-messages` field from config or cmdline, or default - **experimental-offers** (boolean, optional): `experimental-offers` field from config or cmdline, or default - **experimental-shutdown-wrong-funding** (boolean, optional): `experimental-shutdown-wrong-funding` field from config or cmdline, or default - **experimental-websocket-port** (u16, optional): `experimental-websocket-port` field from config or cmdline, or default diff --git a/doc/lightning-sendcustommsg.7.md b/doc/lightning-sendcustommsg.7.md index 5d3b8492046a..5058fd08deea 100644 --- a/doc/lightning-sendcustommsg.7.md +++ b/doc/lightning-sendcustommsg.7.md @@ -16,8 +16,9 @@ top, not for direct use by end-users. The message must be a hex encoded well-formed message, including the 2-byte type prefix, but excluding the length prefix which will be added by the RPC -method. The messages must not use even-numbered types, since these may require -synchronous handling on the receiving side, and can cause the connection to be +method. The messages must not use even-numbered types, unless using +`--experimental-all-onion-messages`, since these may require synchronous +handling on the receiving side, and can cause the connection to be dropped. The message types may also not use one of the internally handled types, since that may cause issues with the internal state tracking of Core Lightning. diff --git a/doc/lightningd-config.5.md b/doc/lightningd-config.5.md index 5fc07bea9388..5090b34236af 100644 --- a/doc/lightningd-config.5.md +++ b/doc/lightningd-config.5.md @@ -535,6 +535,11 @@ be listed with `lightningd --list-features-only`. Specifying this enables sending, forwarding and receiving onion messages, which are in draft status in the BOLT specifications. + **experimental-all-onion-messages** + +Specifying this enables the same as **experimental-onion-messages**, +but also allows even numbered messages to be sent. + **experimental-offers** Specifying this enables the `offers` and `fetchinvoice` plugins and diff --git a/doc/schemas/listconfigs.schema.json b/doc/schemas/listconfigs.schema.json index c3215e8e9ed2..5b41e36fec1e 100644 --- a/doc/schemas/listconfigs.schema.json +++ b/doc/schemas/listconfigs.schema.json @@ -117,6 +117,10 @@ "type": "boolean", "description": "`experimental-onion-messages` field from config or cmdline, or default" }, + "experimental-all-onion-messages": { + "type": "boolean", + "description": "`experimental-all-onion-messages` field from config or cmdline, or default" + }, "experimental-offers": { "type": "boolean", "description": "`experimental-offers` field from config or cmdline, or default" diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index 0fe75804896b..96f6f663fd47 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -656,13 +656,15 @@ static struct command_result *json_sendcustommsg(struct command *cmd, type, peer_wire_name(type)); } - if (type % 2 == 0) { + if (type % 2 == 0 && !cmd->ld->config.allow_even_custom_message) { return command_fail( cmd, JSONRPC2_INVALID_REQUEST, "Cannot send even-typed %d custom message. Currently " "custom messages are limited to odd-numbered message " "types, as even-numbered types might result in " - "disconnections.", + "disconnections. If you really want to send even custom " + "messages, add the --experimental-all-onion-messages " + "to the lightningd configuration", type); } diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h index 5e3a1edb70b0..9be2d55f2ba8 100644 --- a/lightningd/lightningd.h +++ b/lightningd/lightningd.h @@ -70,6 +70,9 @@ struct config { /* EXPERIMENTAL: offers support */ bool exp_offers; + + /* Do we allow even custom messages to be sent */ + bool allow_even_custom_messages; }; typedef STRMAP(const char *) alt_subdaemon_map; diff --git a/lightningd/options.c b/lightningd/options.c index 34e6f6db4cf9..063013ec3b2c 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -797,6 +797,8 @@ static const struct config testnet_config = { .connection_timeout_secs = 60, .exp_offers = IFEXPERIMENTAL(true, false), + + .allow_even_custom_messages = false, }; /* aka. "Dude, where's my coins?" */ @@ -861,6 +863,8 @@ static const struct config mainnet_config = { .connection_timeout_secs = 60, .exp_offers = IFEXPERIMENTAL(true, false), + + .allow_even_custom_messages = false, }; static void check_config(struct lightningd *ld) @@ -997,6 +1001,12 @@ static char *opt_set_onion_messages(struct lightningd *ld) return NULL; } +static char *opt_set_all_onion_messages(struct lightningd *ld) +{ + ld->config.allow_even_custom_messages = true; + return opt_set_onion_messages(ld); +} + static char *opt_set_shutdown_wrong_funding(struct lightningd *ld) { feature_set_or(ld->our_features, @@ -1063,6 +1073,10 @@ static void register_opts(struct lightningd *ld) opt_set_onion_messages, ld, "EXPERIMENTAL: enable send, receive and relay" " of onion messages"); + opt_register_early_noarg("--experimental-all-onion-messages", + opt_set_all_onion_messages, ld, + "EXPERIMENTAL: enable send, receive and relay" + " of all onion messages"); opt_register_early_noarg("--experimental-offers", opt_set_offers, ld, "EXPERIMENTAL: enable send and receive of offers" @@ -1519,6 +1533,8 @@ static void add_config(struct lightningd *ld, feature_offered(ld->our_features ->bits[INIT_FEATURE], OPT_ONION_MESSAGES)); + } else if (opt->cb == (void *)opt_set_all_onion_messages) { + json_add_bool(response, name0, ld->config.allow_even_custom_messages); } else if (opt->cb == (void *)opt_set_offers) { json_add_bool(response, name0, ld->config.exp_offers); } else if (opt->cb == (void *)opt_set_shutdown_wrong_funding) { diff --git a/tests/test_misc.py b/tests/test_misc.py index 84d2836efb8f..03b1aa70dcee 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -2209,6 +2209,59 @@ def test_sendcustommsg(node_factory): ]) +def test_even_sendcustommsg(node_factory): + """Check that we can send even custommsgs to peers in various states. + + `l2` is the node under test. `l1` has a channel with `l2` and should + therefore be attached to `channeld`. `l4` is just connected, so it should + be attached to `openingd`. `l3` has a channel open, but is disconnected + and we can't send to it. + + """ + opts = {'log-level': 'io', 'experimental-all-onion-messages': None, + 'experimental-accept-extra-tlv-types': '43690', 'plugin': [ + os.path.join(os.path.dirname(__file__), "plugins", "custommsg_b.py"), + os.path.join(os.path.dirname(__file__), "plugins", "custommsg_a.py") + ]} + l1, l2, l3, l4 = node_factory.get_nodes(4, opts=opts) + node_factory.join_nodes([l1, l2, l3]) + l2.connect(l4) + l3.stop() + + # Even-numbered message + msg = hex(43690)[2:] + ('ff' * 30) + 'bb' + + # This should work since the peer is currently owned by `channeld` + l2.rpc.sendcustommsg(l1.info['id'], msg) + l2.daemon.wait_for_log( + r'{peer_id}-{owner}-chan#[0-9]: \[OUT\] {msg}'.format( + owner='channeld', msg=msg, peer_id=l1.info['id'] + ) + ) + l1.daemon.wait_for_log(r'\[IN\] {}'.format(msg)) + l1.daemon.wait_for_logs([ + r'Got custommessage_a {msg} from peer {peer_id}'.format( + msg=msg, peer_id=l2.info['id']), + r'Got custommessage_b {msg} from peer {peer_id}'.format( + msg=msg, peer_id=l2.info['id']) + ]) + + # This should work since the peer is currently owned by `openingd` + l2.rpc.sendcustommsg(l4.info['id'], msg) + l2.daemon.wait_for_log( + r'{peer_id}-{owner}-chan#[0-9]: \[OUT\] {msg}'.format( + owner='openingd', msg=msg, peer_id=l4.info['id'] + ) + ) + l4.daemon.wait_for_log(r'\[IN\] {}'.format(msg)) + l4.daemon.wait_for_logs([ + r'Got custommessage_a {msg} from peer {peer_id}'.format( + msg=msg, peer_id=l2.info['id']), + r'Got custommessage_b {msg} from peer {peer_id}'.format( + msg=msg, peer_id=l2.info['id']), + ]) + + @pytest.mark.developer("needs --dev-force-privkey") def test_getsharedsecret(node_factory): """