common: remove support for pre v0.10.2 onionmessages.

Temporarily disable sendpay_blinding test which uses obsolete onionmsg;
there's still some debate on the PR about how blinded HTLCs will work.

Changelog-EXPERIMENTAL: onionmessage: removed support for v0.10.1 onion messages.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2021-11-30 13:36:04 +10:30
parent 166ee4bac8
commit b74848f6f6
27 changed files with 53 additions and 1271 deletions

View File

@ -2321,7 +2321,6 @@ static void peer_in(struct peer *peer, const u8 *msg)
case WIRE_WARNING:
case WIRE_ERROR:
case WIRE_ONION_MESSAGE:
case WIRE_OBS_ONION_MESSAGE:
abort();
}

View File

@ -11,95 +11,6 @@
#define SUPERVERBOSE(...)
#endif
/* Obsolete version: use enctlv() helper. */
struct onionmsg_path **make_blindedpath(const tal_t *ctx,
const struct pubkey *route,
struct pubkey *initial_blinding,
struct pubkey *final_blinding)
{
struct privkey e;
struct pubkey *pk_e, *b;
struct secret *rho;
struct onionmsg_path **path;
size_t num = tal_count(route);
if (!num)
abort();
/* E(i) */
pk_e = tal_arr(tmpctx, struct pubkey, num);
/* B(i) */
b = tal_arr(tmpctx, struct pubkey, num);
/* rho(i) */
rho = tal_arr(tmpctx, struct secret, num);
randombytes_buf(&e, sizeof(e));
if (!pubkey_from_privkey(&e, &pk_e[0]))
abort();
for (size_t i = 0; i < num; i++) {
struct secret ss;
struct secret hmac;
struct sha256 h;
if (secp256k1_ecdh(secp256k1_ctx, ss.data,
&route[i].pubkey, e.secret.data,
NULL, NULL) != 1)
abort();
subkey_from_hmac("blinded_node_id", &ss, &hmac);
b[i] = route[i];
if (i != 0) {
if (secp256k1_ec_pubkey_tweak_mul(secp256k1_ctx,
&b[i].pubkey, hmac.data) != 1)
abort();
}
subkey_from_hmac("rho", &ss, &rho[i]);
blinding_hash_e_and_ss(&pk_e[i], &ss, &h);
if (i != num-1)
blinding_next_pubkey(&pk_e[i], &h, &pk_e[i+1]);
blinding_next_privkey(&e, &h, &e);
}
*initial_blinding = pk_e[0];
*final_blinding = pk_e[num-1];
path = tal_arr(ctx, struct onionmsg_path *, num);
for (size_t i = 0; i < num; i++) {
path[i] = tal(path, struct onionmsg_path);
path[i]->node_id = b[i];
}
for (size_t i = 0; i < num - 1; i++) {
const unsigned char npub[crypto_aead_chacha20poly1305_ietf_NPUBBYTES] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
struct tlv_encmsg_tlvs *inner;
int ret;
/* Inner is encrypted */
inner = tlv_encmsg_tlvs_new(tmpctx);
/* FIXME: We could support scids, too */
inner->next_node_id = cast_const(struct pubkey *, &route[i+1]);
path[i]->enctlv = tal_arr(path, u8, 0);
towire_encmsg_tlvs(&path[i]->enctlv, inner);
towire_pad(&path[i]->enctlv,
crypto_aead_chacha20poly1305_ietf_ABYTES);
ret = crypto_aead_chacha20poly1305_ietf_encrypt(path[i]->enctlv, NULL,
path[i]->enctlv,
tal_bytelen(path[i]->enctlv) - crypto_aead_chacha20poly1305_ietf_ABYTES,
NULL, 0,
NULL, npub,
rho[i].data);
assert(ret == 0);
}
/* Final one has no enctlv */
path[num-1]->enctlv = NULL;
return path;
}
/* Blinds node_id and calculates next blinding factor. */
static bool blind_node(const struct privkey *blinding,
const struct secret *ss,

View File

@ -10,13 +10,6 @@ struct pubkey;
struct privkey;
struct secret;
/* Fills in *initial_blinding and *final_blinding and returns
* onionmsg_path array for this route */
struct onionmsg_path **make_blindedpath(const tal_t *ctx,
const struct pubkey *route,
struct pubkey *initial_blinding,
struct pubkey *final_blinding);
/**
* create_enctlv - Encrypt an encmsg to form an enctlv.
* @ctx: tal context

View File

@ -144,15 +144,7 @@ int main(int argc, char **argv)
/* Inner is encrypted */
inner = tlv_encmsg_tlvs_new(tmpctx);
/* Use scid if they provided one */
if (scids[i]) {
inner->obs_next_short_channel_id
= tal_dup(inner, struct short_channel_id,
scids[i]);
} else {
inner->next_node_id
= tal_dup(inner, struct pubkey, &nodes[i+1]);
}
inner->next_node_id = tal_dup(inner, struct pubkey, &nodes[i+1]);
p = tal_arr(tmpctx, u8, 0);
towire_encmsg_tlvs(&p, inner);

View File

@ -1514,13 +1514,12 @@ type prefix, since c-lightning does not know how to parse the message.
Because this is a chained hook, the daemon expects the result to be
`{'result': 'continue'}`. It will fail if something else is returned.
### `onion_message`, `onion_message_blinded` and `onion_message_ourpath`
### `onion_message_blinded` and `onion_message_ourpath`
**(WARNING: experimental-offers only)**
These three hooks are almost identical, in that they are called when
an onion message is received. The `onion_message` hook is only used
for obsolete unblinded messages, and can be ignored for modern usage.
These two hooks are almost identical, in that they are called when
an onion message is received.
`onion_message_blinded` is used for unsolicited messages (where the
source knows that it is sending to this node), and
@ -1556,6 +1555,7 @@ The payload for a call follows this format:
All fields shown here are optional.
We suggest just returning `{'result': 'continue'}`; any other result
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
will cause the message not to be handed to any other hooks.
## Bitcoin backend

View File

@ -350,235 +350,6 @@ static bool handle_local_channel_announcement(struct daemon *daemon,
return true;
}
/* Peer sends obsolete onion msg. */
static u8 *handle_obs_onion_message(struct peer *peer, const u8 *msg)
{
enum onion_wire badreason;
struct onionpacket *op;
struct secret ss, *blinding_ss;
struct pubkey *blinding_in, ephemeral;
struct route_step *rs;
u8 *onion;
const u8 *cursor;
size_t max, maxlen;
struct tlv_onionmsg_payload *om;
struct tlv_obs_onion_message_tlvs *tlvs = tlv_obs_onion_message_tlvs_new(msg);
/* Ignore unless explicitly turned on. */
if (!feature_offered(peer->daemon->our_features->bits[NODE_ANNOUNCE_FEATURE],
OPT_ONION_MESSAGES))
return NULL;
/* FIXME: ratelimit! */
if (!fromwire_obs_onion_message(msg, msg, &onion, tlvs))
return towire_warningfmt(peer, NULL, "Bad onion_message");
/* We unwrap the onion now. */
op = parse_onionpacket(tmpctx, onion, tal_bytelen(onion), &badreason);
if (!op) {
status_debug("peer %s: onion msg: can't parse onionpacket: %s",
type_to_string(tmpctx, struct node_id, &peer->id),
onion_wire_name(badreason));
return NULL;
}
ephemeral = op->ephemeralkey;
if (tlvs->blinding) {
struct secret hmac;
/* E(i) */
blinding_in = tal_dup(msg, struct pubkey, tlvs->blinding);
status_debug("peer %s: blinding in = %s",
type_to_string(tmpctx, struct node_id, &peer->id),
type_to_string(tmpctx, struct pubkey, blinding_in));
blinding_ss = tal(msg, struct secret);
ecdh(blinding_in, blinding_ss);
/* b(i) = HMAC256("blinded_node_id", ss(i)) * k(i) */
subkey_from_hmac("blinded_node_id", blinding_ss, &hmac);
/* We instead tweak the *ephemeral* key from the onion and use
* our normal privkey: since hsmd knows only how to ECDH with
* our real key */
if (secp256k1_ec_pubkey_tweak_mul(secp256k1_ctx,
&ephemeral.pubkey,
hmac.data) != 1) {
status_debug("peer %s: onion msg: can't tweak pubkey",
type_to_string(tmpctx, struct node_id, &peer->id));
return NULL;
}
} else {
blinding_ss = NULL;
blinding_in = NULL;
}
ecdh(&ephemeral, &ss);
/* We make sure we can parse onion packet, so we know if shared secret
* is actually valid (this checks hmac). */
rs = process_onionpacket(tmpctx, op, &ss, NULL, 0, false);
if (!rs) {
status_debug("peer %s: onion msg: can't process onionpacket ss=%s",
type_to_string(tmpctx, struct node_id, &peer->id),
type_to_string(tmpctx, struct secret, &ss));
return NULL;
}
/* The raw payload is prepended with length in the TLV world. */
cursor = rs->raw_payload;
max = tal_bytelen(rs->raw_payload);
maxlen = fromwire_bigsize(&cursor, &max);
if (!cursor) {
status_debug("peer %s: onion msg: Invalid hop payload %s",
type_to_string(tmpctx, struct node_id, &peer->id),
tal_hex(tmpctx, rs->raw_payload));
return NULL;
}
if (maxlen > max) {
status_debug("peer %s: onion msg: overlong hop payload %s",
type_to_string(tmpctx, struct node_id, &peer->id),
tal_hex(tmpctx, rs->raw_payload));
return NULL;
}
om = tlv_onionmsg_payload_new(msg);
if (!fromwire_onionmsg_payload(&cursor, &maxlen, om)) {
status_debug("peer %s: onion msg: invalid onionmsg_payload %s",
type_to_string(tmpctx, struct node_id, &peer->id),
tal_hex(tmpctx, rs->raw_payload));
return NULL;
}
/* If we weren't given a blinding factor, tlv can provide one. */
if (om->obs_blinding && !blinding_ss) {
/* E(i) */
blinding_in = tal_dup(msg, struct pubkey, om->obs_blinding);
blinding_ss = tal(msg, struct secret);
ecdh(blinding_in, blinding_ss);
}
if (om->enctlv) {
const unsigned char npub[crypto_aead_chacha20poly1305_ietf_NPUBBYTES] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
u8 *dec;
struct secret rho;
int ret;
if (!blinding_ss) {
status_debug("peer %s: enctlv but no blinding?",
type_to_string(tmpctx, struct node_id, &peer->id));
return NULL;
}
/* We need this to decrypt enctlv */
subkey_from_hmac("rho", blinding_ss, &rho);
/* Overrides next_scid / next_node */
if (tal_bytelen(om->enctlv)
< crypto_aead_chacha20poly1305_ietf_ABYTES) {
status_debug("peer %s: enctlv too short for mac",
type_to_string(tmpctx, struct node_id, &peer->id));
return NULL;
}
dec = tal_arr(msg, u8,
tal_bytelen(om->enctlv)
- crypto_aead_chacha20poly1305_ietf_ABYTES);
ret = crypto_aead_chacha20poly1305_ietf_decrypt(dec, NULL,
NULL,
om->enctlv,
tal_bytelen(om->enctlv),
NULL, 0,
npub,
rho.data);
if (ret != 0) {
status_debug("peer %s: Failed to decrypt enctlv field",
type_to_string(tmpctx, struct node_id, &peer->id));
return NULL;
}
status_debug("peer %s: enctlv -> %s",
type_to_string(tmpctx, struct node_id, &peer->id),
tal_hex(tmpctx, dec));
/* Replace onionmsg with one from enctlv */
cursor = dec;
maxlen = tal_bytelen(dec);
om = tlv_onionmsg_payload_new(msg);
if (!fromwire_onionmsg_payload(&cursor, &maxlen, om)) {
status_debug("peer %s: onion msg: invalid enctlv onionmsg_payload %s",
type_to_string(tmpctx, struct node_id, &peer->id),
tal_hex(tmpctx, dec));
return NULL;
}
} else if (blinding_ss && rs->nextcase != ONION_END) {
status_debug("peer %s: Onion had %s, but not enctlv?",
type_to_string(tmpctx, struct node_id, &peer->id),
tlvs->blinding ? "blinding" : "om blinding");
return NULL;
}
if (rs->nextcase == ONION_END) {
struct pubkey *blinding;
const struct onionmsg_path **path;
u8 *omsg;
if (om->obs_reply_path) {
blinding = &om->obs_reply_path->blinding;
path = cast_const2(const struct onionmsg_path **,
om->obs_reply_path->path);
} else {
blinding = NULL;
path = NULL;
}
/* We re-marshall here by policy, before handing to lightningd */
omsg = tal_arr(tmpctx, u8, 0);
towire_tlvstream_raw(&omsg, om->fields);
daemon_conn_send(peer->daemon->master,
take(towire_gossipd_got_obs_onionmsg_to_us(NULL,
blinding_in,
blinding,
path,
omsg)));
} else {
struct pubkey *next_blinding;
struct node_id *next_node;
/* This *MUST* have instructions on where to go next. */
if (!om->obs_next_short_channel_id && !om->obs_next_node_id) {
status_debug("peer %s: onion msg: no next field in %s",
type_to_string(tmpctx, struct node_id, &peer->id),
tal_hex(tmpctx, rs->raw_payload));
return NULL;
}
if (blinding_ss) {
/* E(i-1) = H(E(i) || ss(i)) * E(i) */
struct sha256 h;
blinding_hash_e_and_ss(blinding_in, blinding_ss, &h);
next_blinding = tal(msg, struct pubkey);
blinding_next_pubkey(blinding_in, &h, next_blinding);
} else
next_blinding = NULL;
if (om->obs_next_node_id) {
next_node = tal(tmpctx, struct node_id);
node_id_from_pubkey(next_node, om->obs_next_node_id);
} else
next_node = NULL;
daemon_conn_send(peer->daemon->master,
take(towire_gossipd_got_obs_onionmsg_forward(NULL,
om->obs_next_short_channel_id,
next_node,
next_blinding,
serialize_onionpacket(tmpctx, rs->next))));
}
return NULL;
}
/* Peer sends onion msg. */
static u8 *handle_onion_message(struct peer *peer, const u8 *msg)
{
@ -727,38 +498,6 @@ static u8 *handle_onion_message(struct peer *peer, const u8 *msg)
return NULL;
}
/* We send an obsolete onion msg. */
static struct io_plan *obs_onionmsg_req(struct io_conn *conn, struct daemon *daemon,
const u8 *msg)
{
struct node_id id;
u8 *onion_routing_packet;
struct pubkey *blinding;
struct peer *peer;
if (!fromwire_gossipd_send_obs_onionmsg(msg, msg, &id, &onion_routing_packet,
&blinding))
master_badmsg(WIRE_GOSSIPD_SEND_OBS_ONIONMSG, msg);
/* Even if lightningd were to check for valid ids, there's a race
* where it might vanish before we read this command; cleaner to
* handle it here with 'sent' = false. */
peer = find_peer(daemon, &id);
if (peer) {
struct tlv_obs_onion_message_tlvs *tlvs;
tlvs = tlv_obs_onion_message_tlvs_new(msg);
if (blinding)
tlvs->blinding = tal_dup(tlvs, struct pubkey, blinding);
queue_peer_msg(peer,
take(towire_obs_onion_message(NULL,
onion_routing_packet,
tlvs)));
}
return daemon_conn_read_next(conn, daemon->master);
}
static struct io_plan *onionmsg_req(struct io_conn *conn, struct daemon *daemon,
const u8 *msg)
{
@ -814,9 +553,6 @@ static struct io_plan *peer_msg_in(struct io_conn *conn,
case WIRE_REPLY_SHORT_CHANNEL_IDS_END:
err = handle_reply_short_channel_ids_end(peer, msg);
goto handled_relay;
case WIRE_OBS_ONION_MESSAGE:
err = handle_obs_onion_message(peer, msg);
goto handled_relay;
case WIRE_ONION_MESSAGE:
err = handle_onion_message(peer, msg);
goto handled_relay;
@ -1587,9 +1323,6 @@ static struct io_plan *recv_req(struct io_conn *conn,
break;
#endif /* !DEVELOPER */
case WIRE_GOSSIPD_SEND_OBS_ONIONMSG:
return obs_onionmsg_req(conn, daemon, msg);
case WIRE_GOSSIPD_SEND_ONIONMSG:
return onionmsg_req(conn, daemon, msg);
@ -1599,8 +1332,6 @@ static struct io_plan *recv_req(struct io_conn *conn,
case WIRE_GOSSIPD_GET_TXOUT:
case WIRE_GOSSIPD_DEV_MEMLEAK_REPLY:
case WIRE_GOSSIPD_DEV_COMPACT_STORE_REPLY:
case WIRE_GOSSIPD_GOT_OBS_ONIONMSG_TO_US:
case WIRE_GOSSIPD_GOT_OBS_ONIONMSG_FORWARD:
case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US:
case WIRE_GOSSIPD_ADDGOSSIP_REPLY:
break;

View File

@ -74,22 +74,6 @@ msgdata,gossipd_dev_compact_store_reply,success,bool,
msgtype,gossipd_new_blockheight,3026
msgdata,gossipd_new_blockheight,blockheight,u32,
# Tell lightningd we got an obsolete onion message (for us, or to fwd)
msgtype,gossipd_got_obs_onionmsg_to_us,3142
msgdata,gossipd_got_obs_onionmsg_to_us,blinding_in,?pubkey,
msgdata,gossipd_got_obs_onionmsg_to_us,reply_blinding,?pubkey,
msgdata,gossipd_got_obs_onionmsg_to_us,reply_path_len,u16,
msgdata,gossipd_got_obs_onionmsg_to_us,reply_path,onionmsg_path,reply_path_len
msgdata,gossipd_got_obs_onionmsg_to_us,rawmsg_len,u16,
msgdata,gossipd_got_obs_onionmsg_to_us,rawmsg,u8,rawmsg_len
msgtype,gossipd_got_obs_onionmsg_forward,3143
msgdata,gossipd_got_obs_onionmsg_forward,next_scid,?short_channel_id,
msgdata,gossipd_got_obs_onionmsg_forward,next_node_id,?node_id,
msgdata,gossipd_got_obs_onionmsg_forward,next_blinding,?pubkey,
msgdata,gossipd_got_obs_onionmsg_forward,next_onion_len,u16,
msgdata,gossipd_got_obs_onionmsg_forward,next_onion,u8,next_onion_len
msgtype,gossipd_got_onionmsg_to_us,3145
msgdata,gossipd_got_onionmsg_to_us,node_alias,pubkey,
msgdata,gossipd_got_onionmsg_to_us,self_id,?secret,
@ -101,12 +85,6 @@ msgdata,gossipd_got_onionmsg_to_us,rawmsg_len,u16,
msgdata,gossipd_got_onionmsg_to_us,rawmsg,u8,rawmsg_len
# Lightningd tells us to send a onion message.
msgtype,gossipd_send_obs_onionmsg,3040
msgdata,gossipd_send_obs_onionmsg,id,node_id,
msgdata,gossipd_send_obs_onionmsg,onion_len,u16,
msgdata,gossipd_send_obs_onionmsg,onion,u8,onion_len
msgdata,gossipd_send_obs_onionmsg,blinding,?pubkey,
msgtype,gossipd_send_onionmsg,3041
msgdata,gossipd_send_onionmsg,id,node_id,
msgdata,gossipd_send_onionmsg,onion_len,u16,

1 #include <common/cryptomsg.h>
74 msgtype,gossipd_got_onionmsg_to_us,3145 msgdata,gossipd_send_onionmsg,blinding,pubkey,
75 msgdata,gossipd_got_onionmsg_to_us,node_alias,pubkey, # Lightningd tells us to inject a gossip message (for addgossip RPC)
76 msgdata,gossipd_got_onionmsg_to_us,self_id,?secret, msgtype,gossipd_addgossip,3044
msgdata,gossipd_got_onionmsg_to_us,reply_blinding,?pubkey,
msgdata,gossipd_got_onionmsg_to_us,reply_first_node,?pubkey,
msgdata,gossipd_got_onionmsg_to_us,reply_path_len,u16,
msgdata,gossipd_got_onionmsg_to_us,reply_path,onionmsg_path,reply_path_len
msgdata,gossipd_got_onionmsg_to_us,rawmsg_len,u16,
msgdata,gossipd_got_onionmsg_to_us,rawmsg,u8,rawmsg_len
# Lightningd tells us to send a onion message.
msgtype,gossipd_send_obs_onionmsg,3040
msgdata,gossipd_send_obs_onionmsg,id,node_id,
msgdata,gossipd_send_obs_onionmsg,onion_len,u16,
msgdata,gossipd_send_obs_onionmsg,onion,u8,onion_len
msgdata,gossipd_send_obs_onionmsg,blinding,?pubkey,
msgtype,gossipd_send_onionmsg,3041
msgdata,gossipd_send_onionmsg,id,node_id,
msgdata,gossipd_send_onionmsg,onion_len,u16,
msgdata,gossipd_send_onionmsg,onion,u8,onion_len
77 msgdata,gossipd_send_onionmsg,blinding,pubkey, msgdata,gossipd_addgossip,len,u16,
78 # Lightningd tells us to inject a gossip message (for addgossip RPC) msgdata,gossipd_addgossip,msg,u8,len
79 msgtype,gossipd_addgossip,3044 # Empty string means no problem.
85
86
87
88
89
90

View File

@ -123,7 +123,6 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)
case WIRE_GOSSIPD_DEV_COMPACT_STORE:
case WIRE_GOSSIPD_DEV_SET_TIME:
case WIRE_GOSSIPD_NEW_BLOCKHEIGHT:
case WIRE_GOSSIPD_SEND_OBS_ONIONMSG:
case WIRE_GOSSIPD_SEND_ONIONMSG:
case WIRE_GOSSIPD_ADDGOSSIP:
/* This is a reply, so never gets through to here. */
@ -134,12 +133,6 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)
case WIRE_GOSSIPD_ADDGOSSIP_REPLY:
break;
case WIRE_GOSSIPD_GOT_OBS_ONIONMSG_TO_US:
handle_obs_onionmsg_to_us(gossip->ld, msg);
break;
case WIRE_GOSSIPD_GOT_OBS_ONIONMSG_FORWARD:
handle_obs_onionmsg_forward(gossip->ld, msg);
break;
case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US:
handle_onionmsg_to_us(gossip->ld, msg);
break;

View File

@ -15,15 +15,11 @@
#include <sodium/randombytes.h>
struct onion_message_hook_payload {
/* Pre-spec or modern? */
bool obsolete;
/* Optional */
struct pubkey *blinding_in; /* obsolete only */
struct pubkey *reply_blinding;
struct onionmsg_path **reply_path;
struct pubkey *reply_first_node; /* non-obsolete only */
struct pubkey *our_alias; /* non-obsolete only */
struct pubkey *reply_first_node;
struct pubkey *our_alias;
struct tlv_onionmsg_payload *om;
};
@ -53,34 +49,16 @@ static void onion_message_serialize(struct onion_message_hook_payload *payload,
struct plugin *plugin)
{
json_object_start(stream, "onion_message");
json_add_bool(stream, "obsolete", payload->obsolete);
if (payload->blinding_in)
json_add_pubkey(stream, "blinding_in", payload->blinding_in);
if (payload->our_alias)
json_add_pubkey(stream, "our_alias", payload->our_alias);
/* Modern style. */
if (payload->reply_first_node) {
json_add_blindedpath(stream, "reply_blindedpath",
payload->reply_blinding,
payload->reply_first_node,
payload->reply_path);
} else if (payload->reply_path) {
json_array_start(stream, "reply_path");
for (size_t i = 0; i < tal_count(payload->reply_path); i++) {
json_object_start(stream, NULL);
json_add_pubkey(stream, "id",
&payload->reply_path[i]->node_id);
if (tal_bytelen(payload->reply_path[i]->enctlv) != 0)
json_add_hex_talarr(stream, "enctlv",
payload->reply_path[i]->enctlv);
if (i == 0)
json_add_pubkey(stream, "blinding",
payload->reply_blinding);
json_object_end(stream);
}
json_array_end(stream);
}
/* Common convenience fields */
if (payload->om->invoice_request)
json_add_hex_talarr(stream, "invoice_request",
@ -117,12 +95,6 @@ onion_message_hook_cb(struct onion_message_hook_payload *payload STEALS)
/* Two hooks, because it's critical we only accept blinding if we expect that
* exact blinding key. Otherwise, we can be probed using old blinded paths. */
REGISTER_PLUGIN_HOOK(onion_message,
plugin_hook_continue,
onion_message_hook_cb,
onion_message_serialize,
struct onion_message_hook_payload *);
REGISTER_PLUGIN_HOOK(onion_message_blinded,
plugin_hook_continue,
onion_message_hook_cb,
@ -135,96 +107,6 @@ REGISTER_PLUGIN_HOOK(onion_message_ourpath,
onion_message_serialize,
struct onion_message_hook_payload *);
void handle_obs_onionmsg_to_us(struct lightningd *ld, const u8 *msg)
{
struct onion_message_hook_payload *payload;
u8 *submsg;
size_t submsglen;
const u8 *subptr;
#if DEVELOPER
if (ld->dev_ignore_obsolete_onion)
return;
#endif
payload = tal(ld, struct onion_message_hook_payload);
payload->obsolete = true;
payload->reply_first_node = NULL;
payload->om = tlv_onionmsg_payload_new(payload);
payload->our_alias = NULL;
if (!fromwire_gossipd_got_obs_onionmsg_to_us(payload, msg,
&payload->blinding_in,
&payload->reply_blinding,
&payload->reply_path,
&submsg)) {
log_broken(ld->log, "bad got_onionmsg_tous: %s",
tal_hex(tmpctx, msg));
return;
}
submsglen = tal_bytelen(submsg);
subptr = submsg;
if (!fromwire_onionmsg_payload(&subptr,
&submsglen, payload->om)) {
tal_free(payload);
log_broken(ld->log, "bad got_onionmsg_tous om: %s",
tal_hex(tmpctx, msg));
return;
}
tal_free(submsg);
if (payload->reply_path && !payload->reply_blinding) {
log_broken(ld->log,
"No reply blinding, ignoring reply path");
payload->reply_path = tal_free(payload->reply_path);
}
log_debug(ld->log, "Got obsolete onionmsg%s%s",
payload->reply_blinding ? " reply_blinding": "",
payload->reply_path ? " reply_path": "");
if (payload->blinding_in)
plugin_hook_call_onion_message_blinded(ld, payload);
else
plugin_hook_call_onion_message(ld, payload);
}
void handle_obs_onionmsg_forward(struct lightningd *ld, const u8 *msg)
{
struct short_channel_id *next_scid;
struct node_id *next_node;
struct pubkey *next_blinding;
u8 *onion;
if (!fromwire_gossipd_got_obs_onionmsg_forward(msg, msg, &next_scid,
&next_node,
&next_blinding, &onion)) {
log_broken(ld->log, "bad got_onionmsg_forward: %s",
tal_hex(tmpctx, msg));
return;
}
if (next_scid) {
struct channel *outchan = any_channel_by_scid(ld, next_scid);
if (outchan)
next_node = &outchan->peer->id;
}
if (!next_node) {
log_debug(ld->log, "Cannot forward onionmsg to %s",
next_scid ? type_to_string(tmpctx,
struct short_channel_id,
next_scid)
: "unspecified dest");
} else {
subd_send_msg(ld->gossip,
take(towire_gossipd_send_obs_onionmsg(NULL,
next_node,
onion,
next_blinding)));
}
}
void handle_onionmsg_to_us(struct lightningd *ld, const u8 *msg)
{
struct onion_message_hook_payload *payload;
@ -233,15 +115,8 @@ void handle_onionmsg_to_us(struct lightningd *ld, const u8 *msg)
size_t submsglen;
const u8 *subptr;
#if DEVELOPER
if (ld->dev_ignore_modern_onion)
return;
#endif
payload = tal(ld, struct onion_message_hook_payload);
payload->obsolete = false;
payload->om = tlv_onionmsg_payload_new(payload);
payload->blinding_in = NULL;
payload->our_alias = tal(payload, struct pubkey);
if (!fromwire_gossipd_got_onionmsg_to_us(payload, msg,
@ -290,290 +165,6 @@ void handle_onionmsg_to_us(struct lightningd *ld, const u8 *msg)
plugin_hook_call_onion_message_blinded(ld, payload);
}
struct hop {
struct pubkey id;
struct short_channel_id *scid;
struct pubkey *blinding;
u8 *enctlv;
u8 *invoice;
u8 *invoice_req;
u8 *invoice_err;
u8 *rawtlv;
};
static struct command_result *param_hops(struct command *cmd,
const char *name,
const char *buffer,
const jsmntok_t *tok,
struct hop **hops)
{
size_t i;
const jsmntok_t *t;
if (tok->type != JSMN_ARRAY || tok->size == 0)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%s must be an (non-empty) array", name);
*hops = tal_arr(cmd, struct hop, tok->size);
json_for_each_arr(i, t, tok) {
const jsmntok_t *tid, *tscid, *tblinding, *tenctlv, *trawtlv,
*tinvoice, *tinvoicereq, *tinvoiceerr;
tid = json_get_member(buffer, t, "id");
if (!tid)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%s[%zu] does not have 'id'",
name, i);
tscid = json_get_member(buffer, t, "short_channel_id");
tblinding = json_get_member(buffer, t, "blinding");
tenctlv = json_get_member(buffer, t, "enctlv");
tinvoice = json_get_member(buffer, t, "invoice");
tinvoicereq = json_get_member(buffer, t, "invoice_request");
tinvoiceerr = json_get_member(buffer, t, "invoice_error");
trawtlv = json_get_member(buffer, t, "rawtlv");
if (trawtlv && (tscid || tblinding || tenctlv || tinvoice || tinvoicereq))
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%s[%zu] has 'rawtlv' with other fields",
name, i);
if (tblinding) {
(*hops)[i].blinding = tal(*hops, struct pubkey);
if (!json_to_pubkey(buffer, tblinding,
(*hops)[i].blinding))
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%s[%zu] 'blinding' is invalid", name, i);
} else
(*hops)[i].blinding = NULL;
if (!json_to_pubkey(buffer, tid, &(*hops)[i].id))
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%s[%zu] 'id' is invalid", name, i);
if (tscid) {
(*hops)[i].scid = tal(*hops, struct short_channel_id);
if (!json_to_short_channel_id(buffer, tscid,
(*hops)[i].scid))
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%s[%zu] 'short_channel_id' is invalid", name, i);
} else
(*hops)[i].scid = NULL;
if (tenctlv) {
(*hops)[i].enctlv =
json_tok_bin_from_hex(*hops, buffer, tenctlv);
if (!(*hops)[i].enctlv)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%s[%zu] 'enctlv' is invalid", name, i);
} else
(*hops)[i].enctlv = NULL;
if (tinvoice) {
(*hops)[i].invoice =
json_tok_bin_from_hex(*hops, buffer, tinvoice);
if (!(*hops)[i].invoice)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%s[%zu] 'invoice' is invalid", name, i);
} else
(*hops)[i].invoice = NULL;
if (tinvoicereq) {
(*hops)[i].invoice_req =
json_tok_bin_from_hex(*hops, buffer, tinvoicereq);
if (!(*hops)[i].invoice_req)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%s[%zu] 'invoice_request' is invalid", name, i);
} else
(*hops)[i].invoice_req = NULL;
if (tinvoiceerr) {
(*hops)[i].invoice_err =
json_tok_bin_from_hex(*hops, buffer, tinvoiceerr);
if (!(*hops)[i].invoice_err)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%s[%zu] 'invoice_request' is invalid", name, i);
} else
(*hops)[i].invoice_err = NULL;
if (trawtlv) {
(*hops)[i].rawtlv =
json_tok_bin_from_hex(*hops, buffer, trawtlv);
if (!(*hops)[i].rawtlv)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%s[%zu] 'rawtlv' is invalid", name, i);
} else
(*hops)[i].rawtlv = NULL;
}
return NULL;
}
static struct command_result *param_reply_path(struct command *cmd,
const char *name,
const char *buffer,
const jsmntok_t *tok,
struct tlv_onionmsg_payload_obs_reply_path **reply_path)
{
const jsmntok_t *tblinding, *tpath, *t;
size_t i;
*reply_path = tal(cmd, struct tlv_onionmsg_payload_obs_reply_path);
tblinding = json_get_member(buffer, tok, "blinding");
if (!tblinding)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%s has no 'blinding'", name);
if (!json_to_pubkey(buffer, tblinding, &(*reply_path)->blinding))
return command_fail_badparam(cmd, name, buffer, tblinding,
"'blinding' should be valid pubkey");
tpath = json_get_member(buffer, tok, "path");
if (!tpath || tpath->type != JSMN_ARRAY)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%s has no 'path' array", name);
(*reply_path)->path = tal_arr(*reply_path, struct onionmsg_path *,
tpath->size);
json_for_each_arr(i, t, tpath) {
const jsmntok_t *tid, *tenctlv;
struct onionmsg_path *path;
path = (*reply_path)->path[i] = tal((*reply_path)->path,
struct onionmsg_path);
tid = json_get_member(buffer, t, "id");
if (!tid)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%s path[%zu] 'id' is missing",
name, i);
if (!json_to_pubkey(buffer, tid, &path->node_id))
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%s path[%zu] 'id' is invalid",
name, i);
tenctlv = json_get_member(buffer, t, "enctlv");
if (!tenctlv) {
/* Optional for final destination */
if (i != tpath->size - 1)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%s path[%zu] 'enctlv' is missing",
name, i);
path->enctlv = NULL;
} else {
path->enctlv = json_tok_bin_from_hex(path,
buffer, tenctlv);
if (!path->enctlv)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%s path[%zu] 'enctlv' is invalid",
name, i);
}
}
return NULL;
}
/* Generate ->rawtlv if not already supplied. */
static void populate_tlvs(struct hop *hops,
struct tlv_onionmsg_payload_obs_reply_path *reply_path)
{
for (size_t i = 0; i < tal_count(hops); i++) {
struct tlv_onionmsg_payload *tlv;
if (hops[i].rawtlv)
continue;
tlv = tlv_onionmsg_payload_new(tmpctx);
/* If they don't give scid, use next node id */
if (hops[i].scid) {
tlv->obs_next_short_channel_id
= tal_dup(tlv, struct short_channel_id,
hops[i].scid);
} else if (i != tal_count(hops)-1) {
tlv->obs_next_node_id = tal_dup(tlv, struct pubkey,
&hops[i+1].id);
}
if (hops[i].blinding) {
tlv->obs_blinding = tal_dup(tlv, struct pubkey,
hops[i].blinding);
}
/* Note: tal_dup_talarr returns NULL for NULL */
tlv->enctlv = tal_dup_talarr(tlv, u8, hops[i].enctlv);
tlv->invoice = tal_dup_talarr(tlv, u8, hops[i].invoice);
tlv->invoice_request = tal_dup_talarr(tlv, u8,
hops[i].invoice_req);
tlv->invoice_error = tal_dup_talarr(tlv, u8,
hops[i].invoice_err);
if (i == tal_count(hops)-1 && reply_path)
tlv->obs_reply_path = reply_path;
hops[i].rawtlv = tal_arr(hops, u8, 0);
towire_onionmsg_payload(&hops[i].rawtlv, tlv);
}
}
static struct command_result *json_send_obs_onion_message(struct command *cmd,
const char *buffer,
const jsmntok_t *obj UNNEEDED,
const jsmntok_t *params)
{
struct hop *hops;
struct tlv_onionmsg_payload_obs_reply_path *reply_path;
struct sphinx_path *sphinx_path;
struct onionpacket *op;
struct secret *path_secrets;
struct node_id first_id;
size_t onion_size;
if (!param(cmd, buffer, params,
p_req("hops", param_hops, &hops),
p_opt("reply_path", param_reply_path, &reply_path),
NULL))
return command_param_failed();
if (!feature_offered(cmd->ld->our_features->bits[NODE_ANNOUNCE_FEATURE],
OPT_ONION_MESSAGES))
return command_fail(cmd, LIGHTNINGD,
"experimental-onion-messages not enabled");
node_id_from_pubkey(&first_id, &hops[0].id);
/* Sanity check first; gossipd doesn't bother telling us if peer
* can't be reached. */
if (!peer_by_id(cmd->ld, &first_id))
return command_fail(cmd, LIGHTNINGD, "Unknown first peer");
/* Create an onion which encodes this. */
populate_tlvs(hops, reply_path);
sphinx_path = sphinx_path_new(cmd, NULL);
for (size_t i = 0; i < tal_count(hops); i++)
sphinx_add_modern_hop(sphinx_path, &hops[i].id, hops[i].rawtlv);
/* BOLT-onion-message #4:
* - SHOULD set `len` to 1366 or 32834.
*/
if (sphinx_path_payloads_size(sphinx_path) <= ROUTING_INFO_SIZE)
onion_size = ROUTING_INFO_SIZE;
else
onion_size = 32768;
op = create_onionpacket(tmpctx, sphinx_path, onion_size, &path_secrets);
if (!op)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Creating onion failed (tlvs too long?)");
subd_send_msg(cmd->ld->gossip,
take(towire_gossipd_send_obs_onionmsg(NULL, &first_id,
serialize_onionpacket(tmpctx, op),
NULL)));
return command_success(cmd, json_stream_success(cmd));
}
static const struct json_command send_obs_onion_message_command = {
"sendobsonionmessage",
"utility",
json_send_obs_onion_message,
"Send message over {hops} (id, [short_channel_id], [blinding], [enctlv], [invoice], [invoice_request], [invoice_error], [rawtlv]) with optional {reply_path} (blinding, path[id, enctlv])"
};
AUTODATA(json_command, &send_obs_onion_message_command);
struct onion_hop {
struct pubkey node;
u8 *tlv;

View File

@ -5,9 +5,6 @@
struct lightningd;
void handle_obs_onionmsg_to_us(struct lightningd *ld, const u8 *msg);
void handle_obs_onionmsg_forward(struct lightningd *ld, const u8 *msg);
void handle_onionmsg_to_us(struct lightningd *ld, const u8 *msg);
#endif /* LIGHTNING_LIGHTNINGD_ONION_MESSAGE_H */

View File

@ -1286,7 +1286,6 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state)
case WIRE_ANNOUNCEMENT_SIGNATURES:
case WIRE_GOSSIP_TIMESTAMP_FILTER:
case WIRE_ONION_MESSAGE:
case WIRE_OBS_ONION_MESSAGE:
case WIRE_ACCEPT_CHANNEL2:
case WIRE_TX_ADD_INPUT:
case WIRE_TX_REMOVE_INPUT:
@ -1633,7 +1632,6 @@ static bool run_tx_interactive(struct state *state,
case WIRE_ANNOUNCEMENT_SIGNATURES:
case WIRE_GOSSIP_TIMESTAMP_FILTER:
case WIRE_ONION_MESSAGE:
case WIRE_OBS_ONION_MESSAGE:
case WIRE_TX_SIGNATURES:
case WIRE_OPEN_CHANNEL2:
case WIRE_ACCEPT_CHANNEL2:
@ -3687,7 +3685,6 @@ static u8 *handle_peer_in(struct state *state)
case WIRE_ANNOUNCEMENT_SIGNATURES:
case WIRE_GOSSIP_TIMESTAMP_FILTER:
case WIRE_ONION_MESSAGE:
case WIRE_OBS_ONION_MESSAGE:
case WIRE_ACCEPT_CHANNEL2:
case WIRE_TX_ADD_INPUT:
case WIRE_TX_REMOVE_INPUT:

View File

@ -28,9 +28,7 @@ static LIST_HEAD(sent_list);
struct sent {
/* We're in sent_invreqs, awaiting reply. */
struct list_node list;
/* The blinding factor used by reply (obsolete only) */
struct pubkey *reply_blinding;
/* The alias used by reply (modern only) */
/* The alias used by reply */
struct pubkey *reply_alias;
/* The command which sent us. */
struct command *cmd;
@ -49,17 +47,6 @@ struct sent {
u32 wait_timeout;
};
static struct sent *find_sent_by_blinding(const struct pubkey *blinding)
{
struct sent *i;
list_for_each(&sent_list, i, list) {
if (i->reply_blinding && pubkey_eq(i->reply_blinding, blinding))
return i;
}
return NULL;
}
static struct sent *find_sent_by_alias(const struct pubkey *alias)
{
struct sent *i;
@ -443,48 +430,6 @@ static struct command_result *recv_modern_onion_message(struct command *cmd,
return command_hook_success(cmd);
}
static struct command_result *recv_obs_onion_message(struct command *cmd,
const char *buf,
const jsmntok_t *params)
{
const jsmntok_t *om, *blindingtok;
bool obsolete;
struct sent *sent;
struct pubkey blinding;
struct command_result *err;
om = json_get_member(buf, params, "onion_message");
json_to_bool(buf, json_get_member(buf, om, "obsolete"), &obsolete);
if (!obsolete)
return command_hook_success(cmd);
blindingtok = json_get_member(buf, om, "blinding_in");
if (!blindingtok || !json_to_pubkey(buf, blindingtok, &blinding))
return command_hook_success(cmd);
sent = find_sent_by_blinding(&blinding);
if (!sent) {
plugin_log(cmd->plugin, LOG_DBG,
"No match for obsolete onion %.*s",
json_tok_full_len(om),
json_tok_full(buf, om));
return command_hook_success(cmd);
}
plugin_log(cmd->plugin, LOG_DBG, "Received onion message: %.*s",
json_tok_full_len(params),
json_tok_full(buf, params));
err = handle_error(cmd, sent, buf, om);
if (err)
return err;
if (sent->invreq)
return handle_invreq_response(cmd, sent, buf, om);
return command_hook_success(cmd);
}
static void destroy_sent(struct sent *sent)
{
list_del(&sent->list);
@ -681,7 +626,7 @@ static struct pubkey *path_to_node(const tal_t *ctx,
return nodes;
}
/* Marshal arguments for sending obsolete and modern onion messages */
/* Marshal arguments for sending onion messages */
struct sending {
struct sent *sent;
const char *msgfield;
@ -692,63 +637,6 @@ struct sending {
struct sent *sent);
};
/* Send this message down this path, with blinded reply path */
static struct command_result *send_obs_message(struct command *cmd,
const char *buf UNUSED,
const jsmntok_t *result UNUSED,
struct sending *sending)
{
struct pubkey *backwards;
struct onionmsg_path **path;
struct pubkey blinding;
struct out_req *req;
struct sent *sent = sending->sent;
/* FIXME: Maybe we should allow this? */
if (tal_count(sent->path) == 1)
return command_fail(cmd, PAY_ROUTE_NOT_FOUND,
"Refusing to talk to ourselves");
/* Reverse path is offset by one. */
backwards = tal_arr(tmpctx, struct pubkey, tal_count(sent->path) - 1);
for (size_t i = 0; i < tal_count(backwards); i++)
backwards[tal_count(backwards)-1-i] = sent->path[i];
/* Ok, now make reply for onion_message */
sent->reply_blinding = tal(sent, struct pubkey);
path = make_blindedpath(tmpctx, backwards, &blinding,
sent->reply_blinding);
req = jsonrpc_request_start(cmd->plugin, cmd, "sendobsonionmessage",
sending->done,
forward_error,
sent);
json_array_start(req->js, "hops");
for (size_t i = 1; i < tal_count(sent->path); i++) {
json_object_start(req->js, NULL);
json_add_pubkey(req->js, "id", &sent->path[i]);
if (i == tal_count(sent->path) - 1)
json_add_hex_talarr(req->js,
sending->msgfield, sending->msgval);
json_object_end(req->js);
}
json_array_end(req->js);
json_object_start(req->js, "reply_path");
json_add_pubkey(req->js, "blinding", &blinding);
json_array_start(req->js, "path");
for (size_t i = 0; i < tal_count(path); i++) {
json_object_start(req->js, NULL);
json_add_pubkey(req->js, "id", &path[i]->node_id);
if (path[i]->enctlv)
json_add_hex_talarr(req->js, "enctlv", path[i]->enctlv);
json_object_end(req->js);
}
json_array_end(req->js);
json_object_end(req->js);
return send_outreq(cmd->plugin, req);
}
static struct command_result *
send_modern_message(struct command *cmd,
struct tlv_onionmsg_payload_reply_path *reply_path,
@ -810,10 +698,9 @@ send_modern_message(struct command *cmd,
payloads[nhops-1]->reply_path = reply_path;
req = jsonrpc_request_start(cmd->plugin, cmd, "sendonionmessage",
/* We try obsolete msg next */
send_obs_message,
sending->done,
forward_error,
sending);
sending->sent);
json_add_pubkey(req->js, "first_id", &sent->path[1]);
json_add_pubkey(req->js, "blinding", &fwd_blinding);
json_array_start(req->js, "hops");
@ -1942,10 +1829,6 @@ static const char *init(struct plugin *p, const char *buf UNUSED,
}
static const struct plugin_hook hooks[] = {
{
"onion_message_blinded",
recv_obs_onion_message
},
{
"onion_message_ourpath",
recv_modern_onion_message

View File

@ -41,11 +41,11 @@ static struct command_result *sendonionmessage_error(struct command *cmd,
}
/* FIXME: replyfield string interface is to accomodate obsolete API */
static struct command_result *
send_modern_onion_reply(struct command *cmd,
struct tlv_onionmsg_payload_reply_path *reply_path,
const char *replyfield,
const u8 *replydata)
struct command_result *
send_onion_reply(struct command *cmd,
struct tlv_onionmsg_payload_reply_path *reply_path,
const char *replyfield,
const u8 *replydata)
{
struct out_req *req;
size_t nhops = tal_count(reply_path->path);
@ -84,104 +84,17 @@ send_modern_onion_reply(struct command *cmd,
return send_outreq(cmd->plugin, req);
}
struct command_result *WARN_UNUSED_RESULT
send_onion_reply(struct command *cmd,
struct tlv_onionmsg_payload_reply_path *reply_path,
const char *jsonbuf,
const jsmntok_t *replytok,
const char *replyfield,
const u8 *replydata)
{
struct out_req *req;
size_t i;
const jsmntok_t *t;
if (reply_path)
return send_modern_onion_reply(cmd, reply_path,
replyfield, replydata);
plugin_log(cmd->plugin, LOG_DBG, "sending obs reply %s = %s",
replyfield, tal_hex(tmpctx, replydata));
/* Send to requester, using return route. */
req = jsonrpc_request_start(cmd->plugin, cmd, "sendobsonionmessage",
finished, sendonionmessage_error, NULL);
/* Add reply into last hop. */
json_array_start(req->js, "hops");
json_for_each_arr(i, t, replytok) {
size_t j;
const jsmntok_t *t2;
plugin_log(cmd->plugin, LOG_DBG, "hops[%zu/%i]",
i, replytok->size);
json_object_start(req->js, NULL);
json_for_each_obj(j, t2, t)
json_add_tok(req->js,
json_strdup(tmpctx, jsonbuf, t2),
t2+1, jsonbuf);
if (i == replytok->size - 1) {
plugin_log(cmd->plugin, LOG_DBG, "... adding %s",
replyfield);
json_add_hex_talarr(req->js, replyfield, replydata);
}
json_object_end(req->js);
}
json_array_end(req->js);
return send_outreq(cmd->plugin, req);
}
static struct command_result *onion_message_call(struct command *cmd,
const char *buf,
const jsmntok_t *params)
{
const jsmntok_t *om, *invreqtok, *invtok;
if (!offers_enabled)
return command_hook_success(cmd);
om = json_get_member(buf, params, "onion_message");
invreqtok = json_get_member(buf, om, "invoice_request");
if (invreqtok) {
const jsmntok_t *replytok;
replytok = json_get_member(buf, om, "reply_path");
if (replytok && replytok->size > 0)
return handle_invoice_request(cmd, buf,
invreqtok, replytok, NULL);
else
plugin_log(cmd->plugin, LOG_DBG,
"invoice_request without reply_path");
}
invtok = json_get_member(buf, om, "invoice");
if (invtok) {
const jsmntok_t *replytok;
replytok = json_get_member(buf, om, "reply_path");
return handle_invoice(cmd, buf, invtok, replytok, NULL);
}
return command_hook_success(cmd);
}
static struct command_result *onion_message_modern_call(struct command *cmd,
const char *buf,
const jsmntok_t *params)
{
const jsmntok_t *om, *replytok, *invreqtok, *invtok;
bool obsolete;
struct tlv_onionmsg_payload_reply_path *reply_path;
if (!offers_enabled)
return command_hook_success(cmd);
om = json_get_member(buf, params, "onion_message");
json_to_bool(buf, json_get_member(buf, om, "obsolete"), &obsolete);
if (obsolete)
return command_hook_success(cmd);
replytok = json_get_member(buf, om, "reply_blindedpath");
if (replytok) {
reply_path = json_to_reply_path(cmd, buf, replytok);
@ -194,10 +107,11 @@ static struct command_result *onion_message_modern_call(struct command *cmd,
invreqtok = json_get_member(buf, om, "invoice_request");
if (invreqtok) {
const u8 *invreqbin = json_tok_bin_from_hex(tmpctx, buf, invreqtok);
if (reply_path)
return handle_invoice_request(cmd, buf,
invreqtok,
NULL, reply_path);
return handle_invoice_request(cmd,
invreqbin,
reply_path);
else
plugin_log(cmd->plugin, LOG_DBG,
"invoice_request without reply_path");
@ -205,17 +119,15 @@ static struct command_result *onion_message_modern_call(struct command *cmd,
invtok = json_get_member(buf, om, "invoice");
if (invtok) {
return handle_invoice(cmd, buf, invtok, NULL, reply_path);
const u8 *invbin = json_tok_bin_from_hex(tmpctx, buf, invtok);
if (invbin)
return handle_invoice(cmd, invbin, reply_path);
}
return command_hook_success(cmd);
}
static const struct plugin_hook hooks[] = {
{
"onion_message",
onion_message_call
},
{
"onion_message_blinded",
onion_message_modern_call

View File

@ -9,11 +9,7 @@ struct command;
/* Helper to send a reply */
struct command_result *WARN_UNUSED_RESULT
send_onion_reply(struct command *cmd,
/* Preferred */
struct tlv_onionmsg_payload_reply_path *reply_path,
/* Used if reply_path is NULL */
const char *jsonbuf,
const jsmntok_t *replytok,
const char *replyfield,
const u8 *replydata);
#endif /* LIGHTNING_PLUGINS_OFFERS_H */

View File

@ -10,9 +10,7 @@
struct inv {
struct tlv_invoice *inv;
const char *buf;
/* May be NULL */
const jsmntok_t *replytok;
struct tlv_onionmsg_payload_reply_path *reply_path;
/* The offer, once we've looked it up. */
@ -41,7 +39,7 @@ fail_inv_level(struct command *cmd,
plugin_log(cmd->plugin, l, "%s", msg);
/* Only reply if they gave us a path */
if (!inv->replytok && !inv->reply_path)
if (!inv->reply_path)
return command_hook_success(cmd);
/* Don't send back internal error details. */
@ -55,8 +53,7 @@ fail_inv_level(struct command *cmd,
errdata = tal_arr(cmd, u8, 0);
towire_invoice_error(&errdata, err);
return send_onion_reply(cmd, inv->reply_path, inv->buf, inv->replytok,
"invoice_error", errdata);
return send_onion_reply(cmd, inv->reply_path, "invoice_error", errdata);
}
static struct command_result *WARN_UNUSED_RESULT
@ -315,12 +312,9 @@ static struct command_result *listoffers_error(struct command *cmd,
}
struct command_result *handle_invoice(struct command *cmd,
const char *buf,
const jsmntok_t *invtok,
const jsmntok_t *replytok,
struct tlv_onionmsg_payload_reply_path *reply_path)
const u8 *invbin,
struct tlv_onionmsg_payload_reply_path *reply_path STEALS)
{
const u8 *invbin = json_tok_bin_from_hex(cmd, buf, invtok);
size_t len = tal_count(invbin);
struct inv *inv = tal(cmd, struct inv);
struct out_req *req;
@ -328,17 +322,7 @@ struct command_result *handle_invoice(struct command *cmd,
int bad_feature;
struct sha256 m, shash;
if (reply_path) {
inv->buf = NULL;
inv->replytok = NULL;
inv->reply_path = reply_path;
} else {
/* Make a copy of entire buffer, for later. */
inv->buf = tal_dup_arr(inv, char, buf, replytok->end, 0);
inv->replytok = tal_dup_arr(inv, jsmntok_t, replytok,
json_next(replytok) - replytok, 0);
inv->reply_path = NULL;
}
inv->reply_path = tal_steal(inv, reply_path);
inv->inv = tlv_invoice_new(cmd);
if (!fromwire_invoice(&invbin, &len, inv->inv)) {

View File

@ -3,10 +3,8 @@
#include "config.h"
#include <plugins/libplugin.h>
/* We got an onionmessage with an invoice! replytok/reply_path could be NULL. */
/* We got an onionmessage with an invoice! reply_path could be NULL. */
struct command_result *handle_invoice(struct command *cmd,
const char *buf,
const jsmntok_t *invtok,
const jsmntok_t *replytok,
struct tlv_onionmsg_payload_reply_path *reply_path);
const u8 *invbin,
struct tlv_onionmsg_payload_reply_path *reply_path STEALS);
#endif /* LIGHTNING_PLUGINS_OFFERS_INV_HOOK_H */

View File

@ -15,10 +15,6 @@
/* We need to keep the reply path around so we can reply with invoice */
struct invreq {
struct tlv_invoice_request *invreq;
const char *buf;
/* If obsolete style */
const jsmntok_t *replytok;
/* If modern style. */
struct tlv_onionmsg_payload_reply_path *reply_path;
/* The offer, once we've looked it up. */
@ -63,9 +59,7 @@ fail_invreq_level(struct command *cmd,
errdata = tal_arr(cmd, u8, 0);
towire_invoice_error(&errdata, err);
return send_onion_reply(cmd, invreq->reply_path,
invreq->buf, invreq->replytok,
"invoice_error", errdata);
return send_onion_reply(cmd, invreq->reply_path, "invoice_error", errdata);
}
static struct command_result *WARN_UNUSED_RESULT PRINTF_FMT(3,4)
@ -184,8 +178,7 @@ static struct command_result *createinvoice_done(struct command *cmd,
json_tok_full(buf, t));
}
return send_onion_reply(cmd, ir->reply_path, ir->buf, ir->replytok,
"invoice", rawinv);
return send_onion_reply(cmd, ir->reply_path, "invoice", rawinv);
}
static struct command_result *createinvoice_error(struct command *cmd,
@ -836,28 +829,15 @@ static struct command_result *handle_offerless_request(struct command *cmd,
}
struct command_result *handle_invoice_request(struct command *cmd,
const char *buf,
const jsmntok_t *invreqtok,
const jsmntok_t *replytok,
const u8 *invreqbin,
struct tlv_onionmsg_payload_reply_path *reply_path)
{
const u8 *invreqbin = json_tok_bin_from_hex(cmd, buf, invreqtok);
size_t len = tal_count(invreqbin);
struct invreq *ir = tal(cmd, struct invreq);
struct out_req *req;
int bad_feature;
/* Make a copy of entire buffer, for later. */
if (reply_path) {
ir->buf = NULL;
ir->replytok = NULL;
ir->reply_path = reply_path;
} else {
ir->buf = tal_dup_arr(ir, char, buf, replytok->end, 0);
ir->replytok = tal_dup_arr(ir, jsmntok_t, replytok,
json_next(replytok) - replytok, 0);
ir->reply_path = NULL;
}
ir->reply_path = tal_steal(ir, reply_path);
ir->invreq = tlv_invoice_request_new(cmd);
if (!fromwire_invoice_request(&invreqbin, &len, ir->invreq)) {

View File

@ -7,10 +7,6 @@ extern u32 cltv_final;
/* We got an onionmessage with an invreq! */
struct command_result *handle_invoice_request(struct command *cmd,
const char *buf,
const jsmntok_t *invreqtok,
/* Obsolete onion */
const jsmntok_t *replytok,
/* Modern onion */
struct tlv_onionmsg_payload_reply_path *reply_path);
const u8 *invreqbin,
struct tlv_onionmsg_payload_reply_path *reply_path STEALS);
#endif /* LIGHTNING_PLUGINS_OFFERS_INVREQ_HOOK_H */

View File

@ -2252,77 +2252,6 @@ def test_sendcustommsg(node_factory):
])
def test_sendobsonionmessage(node_factory):
l1, l2, l3 = node_factory.line_graph(3, opts={'experimental-onion-messages': None})
blindedpathtool = os.path.join(os.path.dirname(__file__), "..", "devtools", "blindedpath")
l1.rpc.call('sendobsonionmessage',
{'hops':
[{'id': l2.info['id']},
{'id': l3.info['id']}]})
assert l3.daemon.wait_for_log('Got obsolete onionmsg')
# Now by SCID.
l1.rpc.call('sendobsonionmessage',
{'hops':
[{'id': l2.info['id'],
'short_channel_id': l2.get_channel_scid(l3)},
{'id': l3.info['id']}]})
assert l3.daemon.wait_for_log('Got obsolete onionmsg')
# Now test blinded path.
output = subprocess.check_output(
[blindedpathtool, '--simple-output', 'create', l2.info['id'], l3.info['id']]
).decode('ASCII').strip()
# First line is blinding, then <peerid> then <encblob>.
blinding, p1, p1enc, p2 = output.split('\n')
# First hop can't be blinded!
assert p1 == l2.info['id']
l1.rpc.call('sendobsonionmessage',
{'hops':
[{'id': l2.info['id'],
'blinding': blinding,
'enctlv': p1enc},
{'id': p2}]})
assert l3.daemon.wait_for_log('Got obsolete onionmsg')
@unittest.skipIf(not EXPERIMENTAL_FEATURES, "Needs sendobsonionmessage")
def test_sendobsonionmessage_reply(node_factory):
blindedpathtool = os.path.join(os.path.dirname(__file__), "..", "devtools", "blindedpath")
plugin = os.path.join(os.path.dirname(__file__), "plugins", "onionmessage-reply.py")
l1, l2, l3 = node_factory.line_graph(3, opts={'plugin': plugin})
# Make reply path
output = subprocess.check_output(
[blindedpathtool, '--simple-output', 'create', l2.info['id'], l1.info['id']]
).decode('ASCII').strip()
# First line is blinding, then <peerid> then <encblob>.
blinding, p1, p1enc, p2 = output.split('\n')
# First hop can't be blinded!
assert p1 == l2.info['id']
# Also tests oversize payload which won't fit in 1366-byte onion.
l1.rpc.call('sendobsonionmessage',
{'hops':
[{'id': l2.info['id']},
{'id': l3.info['id'],
'invoice': '77' * 15000}],
'reply_path':
{'blinding': blinding,
'path': [{'id': p1, 'enctlv': p1enc}, {'id': p2}]}})
assert l3.daemon.wait_for_log('Got obsolete onionmsg reply_blinding reply_path')
assert l3.daemon.wait_for_log("Got onion_message invoice '{}'".format('77' * 15000))
assert l3.daemon.wait_for_log('Sent reply via')
assert l1.daemon.wait_for_log('Got obsolete onionmsg')
@pytest.mark.developer("needs --dev-force-privkey")
def test_getsharedsecret(node_factory):
"""

View File

@ -3259,6 +3259,7 @@ def test_reject_invalid_payload(node_factory):
l1.rpc.waitsendpay(inv['payment_hash'])
@pytest.mark.skip("Needs to be updated for modern onion")
@unittest.skipIf(not EXPERIMENTAL_FEATURES, "Needs blinding args to sendpay")
def test_sendpay_blinding(node_factory):
l1, l2, l3, l4 = node_factory.line_graph(4)
@ -4351,23 +4352,6 @@ def test_fetchinvoice_3hop(node_factory, bitcoind):
l1.rpc.call('fetchinvoice', {'offer': offer1['bolt12']})
# Test with obsolete onion.
l4.stop()
l4.daemon.opts['dev-no-modern-onion'] = None
l4.start()
l4.rpc.connect(l3.info['id'], 'localhost', l3.port)
l1.rpc.call('fetchinvoice', {'offer': offer1['bolt12']})
# Test with modern onion.
l4.stop()
del l4.daemon.opts['dev-no-modern-onion']
l4.daemon.opts['dev-no-obsolete-onion'] = None
l4.start()
l4.rpc.connect(l3.info['id'], 'localhost', l3.port)
l1.rpc.call('fetchinvoice', {'offer': offer1['bolt12']})
def test_fetchinvoice(node_factory, bitcoind):
# We remove the conversion plugin on l3, causing it to get upset.

View File

@ -1,30 +1,29 @@
--- wire/extracted_onion_wire_csv 2020-03-25 10:24:12.861645774 +1030
+++ - 2020-03-26 13:47:13.498294435 +1030
@@ -8,6 +8,31 @@
@@ -8,6 +8,30 @@
tlvtype,tlv_payload,payment_data,8
tlvdata,tlv_payload,payment_data,payment_secret,byte,32
tlvdata,tlv_payload,payment_data,total_msat,tu64,
+tlvtype,onionmsg_payload,obs_next_node_id,4
+tlvdata,onionmsg_payload,obs_next_node_id,node_id,point,
+tlvtype,onionmsg_payload,obs_next_short_channel_id,6
+tlvdata,onionmsg_payload,obs_next_short_channel_id,short_channel_id,short_channel_id,
+tlvtype,onionmsg_payload,obs_reply_path,8
+tlvdata,onionmsg_payload,obs_reply_path,blinding,point,
+tlvdata,onionmsg_payload,obs_reply_path,path,onionmsg_path,...
+tlvtype,onionmsg_payload,reply_path,2
+tlvdata,onionmsg_payload,reply_path,first_node_id,point,
+tlvdata,onionmsg_payload,reply_path,blinding,point,
+tlvdata,onionmsg_payload,reply_path,path,onionmsg_path,...
+tlvtype,onionmsg_payload,enctlv,10
+tlvdata,onionmsg_payload,enctlv,enctlv,byte,...
+tlvtype,onionmsg_payload,obs_blinding,12
+tlvdata,onionmsg_payload,obs_blinding,blinding,point,
+tlvtype,onionmsg_payload,invoice_request,64
+tlvdata,onionmsg_payload,invoice_request,invoice_request,byte,...
+tlvtype,onionmsg_payload,invoice,66
+tlvdata,onionmsg_payload,invoice,invoice,byte,...
+tlvtype,onionmsg_payload,invoice_error,68
+tlvdata,onionmsg_payload,invoice_error,invoice_error,byte,...
+tlvtype,encmsg_tlvs,padding,1
+tlvdata,encmsg_tlvs,padding,pad,byte,...
+tlvtype,encmsg_tlvs,next_node_id,4
+tlvdata,encmsg_tlvs,next_node_id,node_id,point,
+tlvtype,encmsg_tlvs,obs_next_short_channel_id,6
+tlvdata,encmsg_tlvs,obs_next_short_channel_id,short_channel_id,short_channel_id,
+tlvtype,encmsg_tlvs,next_blinding,12
+tlvdata,encmsg_tlvs,next_blinding,blinding,point,
+tlvtype,encmsg_tlvs,self_id,14
+tlvdata,encmsg_tlvs,self_id,data,byte,...
+subtype,onionmsg_path
+subtypedata,onionmsg_path,node_id,point,
+subtypedata,onionmsg_path,enclen,u16,

View File

@ -1,30 +0,0 @@
--- onion_wire.csv 2021-08-25 12:41:02.872253965 +0930
+++ onion_wire.csv.raw 2021-08-25 13:52:00.748767887 +0930
@@ -8,6 +8,10 @@ tlvdata,tlv_payload,short_channel_id,short_channel_id,short_channel_id,
tlvtype,tlv_payload,payment_data,8
tlvdata,tlv_payload,payment_data,payment_secret,byte,32
tlvdata,tlv_payload,payment_data,total_msat,tu64,
+tlvtype,onionmsg_payload,reply_path,2
+tlvdata,onionmsg_payload,reply_path,first_node_id,point,
+tlvdata,onionmsg_payload,reply_path,blinding,point,
+tlvdata,onionmsg_payload,reply_path,path,onionmsg_path,...
tlvtype,onionmsg_payload,obs_next_node_id,4
tlvdata,onionmsg_payload,obs_next_node_id,node_id,point,
tlvtype,onionmsg_payload,obs_next_short_channel_id,6
@@ -29,10 +29,16 @@ tlvtype,onionmsg_payload,invoice,66
tlvdata,onionmsg_payload,invoice,invoice,byte,...
tlvtype,onionmsg_payload,invoice_error,68
tlvdata,onionmsg_payload,invoice_error,invoice_error,byte,...
+tlvtype,encmsg_tlvs,padding,1
+tlvdata,encmsg_tlvs,padding,pad,byte,...
tlvtype,encmsg_tlvs,next_node_id,4
tlvdata,encmsg_tlvs,next_node_id,node_id,point,
tlvtype,encmsg_tlvs,obs_next_short_channel_id,6
tlvdata,encmsg_tlvs,obs_next_short_channel_id,short_channel_id,short_channel_id,
+tlvtype,encmsg_tlvs,next_blinding,12
+tlvdata,encmsg_tlvs,next_blinding,blinding,point,
+tlvtype,encmsg_tlvs,self_id,14
+tlvdata,encmsg_tlvs,self_id,data,byte,...
subtype,onionmsg_path
subtypedata,onionmsg_path,node_id,point,
subtypedata,onionmsg_path,enclen,u16,

View File

@ -1,12 +0,0 @@
--- wire/extracted_peer_wire_csv 2020-03-11 10:30:35.744376417 +1030
+++ - 2020-03-26 13:47:13.409755567 +1030
@@ -211,3 +211,9 @@
msgdata,gossip_timestamp_filter,chain_hash,chain_hash,
msgdata,gossip_timestamp_filter,first_timestamp,u32,
msgdata,gossip_timestamp_filter,timestamp_range,u32,
+msgtype,obs_onion_message,385,option_onion_messages
+msgdata,obs_onion_message,len,u16,
+msgdata,obs_onion_message,onionmsg,byte,len
+msgdata,obs_onion_message,obs_onion_message_tlvs,obs_onion_message_tlvs,
+tlvtype,obs_onion_message_tlvs,blinding,2
+tlvdata,obs_onion_message_tlvs,blinding,blinding,point,

View File

@ -1,9 +1,9 @@
--- peer_wire.csv 2021-08-25 12:41:02.876254003 +0930
+++ peer_wire.csv.raw 2021-08-25 13:42:31.991693809 +0930
@@ -320,3 +210,7 @@
msgdata,obs_onion_message,obs_onion_message_tlvs,obs_onion_message_tlvs,
tlvtype,obs_onion_message_tlvs,blinding,2
tlvdata,obs_onion_message_tlvs,blinding,blinding,point,
msgdata,gossip_timestamp_filter,chain_hash,chain_hash,
msgdata,gossip_timestamp_filter,first_timestamp,u32,
msgdata,gossip_timestamp_filter,timestamp_range,u32,
+msgtype,onion_message,387,option_onion_messages
+msgdata,onion_message,blinding,point,
+msgdata,onion_message,len,u16,

View File

@ -12,17 +12,8 @@ tlvtype,onionmsg_payload,reply_path,2
tlvdata,onionmsg_payload,reply_path,first_node_id,point,
tlvdata,onionmsg_payload,reply_path,blinding,point,
tlvdata,onionmsg_payload,reply_path,path,onionmsg_path,...
tlvtype,onionmsg_payload,obs_next_node_id,4
tlvdata,onionmsg_payload,obs_next_node_id,node_id,point,
tlvtype,onionmsg_payload,obs_next_short_channel_id,6
tlvdata,onionmsg_payload,obs_next_short_channel_id,short_channel_id,short_channel_id,
tlvtype,onionmsg_payload,obs_reply_path,8
tlvdata,onionmsg_payload,obs_reply_path,blinding,point,
tlvdata,onionmsg_payload,obs_reply_path,path,onionmsg_path,...
tlvtype,onionmsg_payload,enctlv,10
tlvdata,onionmsg_payload,enctlv,enctlv,byte,...
tlvtype,onionmsg_payload,obs_blinding,12
tlvdata,onionmsg_payload,obs_blinding,blinding,point,
tlvtype,onionmsg_payload,invoice_request,64
tlvdata,onionmsg_payload,invoice_request,invoice_request,byte,...
tlvtype,onionmsg_payload,invoice,66
@ -33,8 +24,6 @@ tlvtype,encmsg_tlvs,padding,1
tlvdata,encmsg_tlvs,padding,pad,byte,...
tlvtype,encmsg_tlvs,next_node_id,4
tlvdata,encmsg_tlvs,next_node_id,node_id,point,
tlvtype,encmsg_tlvs,obs_next_short_channel_id,6
tlvdata,encmsg_tlvs,obs_next_short_channel_id,short_channel_id,short_channel_id,
tlvtype,encmsg_tlvs,next_blinding,12
tlvdata,encmsg_tlvs,next_blinding,blinding,point,
tlvtype,encmsg_tlvs,self_id,14

1 #include <wire/onion_defs.h>
12 tlvdata,onionmsg_payload,reply_path,first_node_id,point,
13 tlvdata,onionmsg_payload,reply_path,blinding,point,
14 tlvdata,onionmsg_payload,reply_path,path,onionmsg_path,...
tlvtype,onionmsg_payload,obs_next_node_id,4
tlvdata,onionmsg_payload,obs_next_node_id,node_id,point,
tlvtype,onionmsg_payload,obs_next_short_channel_id,6
tlvdata,onionmsg_payload,obs_next_short_channel_id,short_channel_id,short_channel_id,
tlvtype,onionmsg_payload,obs_reply_path,8
tlvdata,onionmsg_payload,obs_reply_path,blinding,point,
tlvdata,onionmsg_payload,obs_reply_path,path,onionmsg_path,...
15 tlvtype,onionmsg_payload,enctlv,10
16 tlvdata,onionmsg_payload,enctlv,enctlv,byte,...
tlvtype,onionmsg_payload,obs_blinding,12
tlvdata,onionmsg_payload,obs_blinding,blinding,point,
17 tlvtype,onionmsg_payload,invoice_request,64
18 tlvdata,onionmsg_payload,invoice_request,invoice_request,byte,...
19 tlvtype,onionmsg_payload,invoice,66
24 tlvdata,encmsg_tlvs,padding,pad,byte,...
25 tlvtype,encmsg_tlvs,next_node_id,4
26 tlvdata,encmsg_tlvs,next_node_id,node_id,point,
tlvtype,encmsg_tlvs,obs_next_short_channel_id,6
tlvdata,encmsg_tlvs,obs_next_short_channel_id,short_channel_id,short_channel_id,
27 tlvtype,encmsg_tlvs,next_blinding,12
28 tlvdata,encmsg_tlvs,next_blinding,blinding,point,
29 tlvtype,encmsg_tlvs,self_id,14

View File

@ -34,7 +34,6 @@ static bool unknown_type(enum peer_wire t)
case WIRE_REPLY_CHANNEL_RANGE:
case WIRE_GOSSIP_TIMESTAMP_FILTER:
case WIRE_ONION_MESSAGE:
case WIRE_OBS_ONION_MESSAGE:
case WIRE_TX_ADD_INPUT:
case WIRE_TX_REMOVE_INPUT:
case WIRE_TX_ADD_OUTPUT:
@ -64,7 +63,6 @@ bool is_msg_for_gossipd(const u8 *cursor)
case WIRE_QUERY_CHANNEL_RANGE:
case WIRE_REPLY_CHANNEL_RANGE:
case WIRE_ONION_MESSAGE:
case WIRE_OBS_ONION_MESSAGE:
return true;
case WIRE_WARNING:
case WIRE_INIT:

View File

@ -328,12 +328,6 @@ msgtype,gossip_timestamp_filter,265,gossip_queries
msgdata,gossip_timestamp_filter,chain_hash,chain_hash,
msgdata,gossip_timestamp_filter,first_timestamp,u32,
msgdata,gossip_timestamp_filter,timestamp_range,u32,
msgtype,obs_onion_message,385,option_onion_messages
msgdata,obs_onion_message,len,u16,
msgdata,obs_onion_message,onionmsg,byte,len
msgdata,obs_onion_message,obs_onion_message_tlvs,obs_onion_message_tlvs,
tlvtype,obs_onion_message_tlvs,blinding,2
tlvdata,obs_onion_message_tlvs,blinding,blinding,point,
msgtype,onion_message,387,option_onion_messages
msgdata,onion_message,blinding,point,
msgdata,onion_message,len,u16,

1 msgtype,init,16
328 msgdata,gossip_timestamp_filter,chain_hash,chain_hash,
329 msgdata,gossip_timestamp_filter,first_timestamp,u32,
330 msgdata,gossip_timestamp_filter,timestamp_range,u32,
msgtype,obs_onion_message,385,option_onion_messages
msgdata,obs_onion_message,len,u16,
msgdata,obs_onion_message,onionmsg,byte,len
msgdata,obs_onion_message,obs_onion_message_tlvs,obs_onion_message_tlvs,
tlvtype,obs_onion_message_tlvs,blinding,2
tlvdata,obs_onion_message_tlvs,blinding,blinding,point,
331 msgtype,onion_message,387,option_onion_messages
332 msgdata,onion_message,blinding,point,
333 msgdata,onion_message,len,u16,