mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 01:43:36 +01:00
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:
parent
166ee4bac8
commit
b74848f6f6
@ -2321,7 +2321,6 @@ static void peer_in(struct peer *peer, const u8 *msg)
|
|||||||
case WIRE_WARNING:
|
case WIRE_WARNING:
|
||||||
case WIRE_ERROR:
|
case WIRE_ERROR:
|
||||||
case WIRE_ONION_MESSAGE:
|
case WIRE_ONION_MESSAGE:
|
||||||
case WIRE_OBS_ONION_MESSAGE:
|
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,95 +11,6 @@
|
|||||||
#define SUPERVERBOSE(...)
|
#define SUPERVERBOSE(...)
|
||||||
#endif
|
#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. */
|
/* Blinds node_id and calculates next blinding factor. */
|
||||||
static bool blind_node(const struct privkey *blinding,
|
static bool blind_node(const struct privkey *blinding,
|
||||||
const struct secret *ss,
|
const struct secret *ss,
|
||||||
|
@ -10,13 +10,6 @@ struct pubkey;
|
|||||||
struct privkey;
|
struct privkey;
|
||||||
struct secret;
|
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.
|
* create_enctlv - Encrypt an encmsg to form an enctlv.
|
||||||
* @ctx: tal context
|
* @ctx: tal context
|
||||||
|
@ -144,15 +144,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
/* Inner is encrypted */
|
/* Inner is encrypted */
|
||||||
inner = tlv_encmsg_tlvs_new(tmpctx);
|
inner = tlv_encmsg_tlvs_new(tmpctx);
|
||||||
/* Use scid if they provided one */
|
inner->next_node_id = tal_dup(inner, struct pubkey, &nodes[i+1]);
|
||||||
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]);
|
|
||||||
}
|
|
||||||
p = tal_arr(tmpctx, u8, 0);
|
p = tal_arr(tmpctx, u8, 0);
|
||||||
towire_encmsg_tlvs(&p, inner);
|
towire_encmsg_tlvs(&p, inner);
|
||||||
|
|
||||||
|
@ -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
|
Because this is a chained hook, the daemon expects the result to be
|
||||||
`{'result': 'continue'}`. It will fail if something else is returned.
|
`{'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)**
|
**(WARNING: experimental-offers only)**
|
||||||
|
|
||||||
These three hooks are almost identical, in that they are called when
|
These two hooks are almost identical, in that they are called when
|
||||||
an onion message is received. The `onion_message` hook is only used
|
an onion message is received.
|
||||||
for obsolete unblinded messages, and can be ignored for modern usage.
|
|
||||||
|
|
||||||
`onion_message_blinded` is used for unsolicited messages (where the
|
`onion_message_blinded` is used for unsolicited messages (where the
|
||||||
source knows that it is sending to this node), and
|
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.
|
All fields shown here are optional.
|
||||||
|
|
||||||
We suggest just returning `{'result': 'continue'}`; any other result
|
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.
|
will cause the message not to be handed to any other hooks.
|
||||||
|
|
||||||
## Bitcoin backend
|
## Bitcoin backend
|
||||||
|
@ -350,235 +350,6 @@ static bool handle_local_channel_announcement(struct daemon *daemon,
|
|||||||
return true;
|
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. */
|
/* Peer sends onion msg. */
|
||||||
static u8 *handle_onion_message(struct peer *peer, const u8 *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;
|
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,
|
static struct io_plan *onionmsg_req(struct io_conn *conn, struct daemon *daemon,
|
||||||
const u8 *msg)
|
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:
|
case WIRE_REPLY_SHORT_CHANNEL_IDS_END:
|
||||||
err = handle_reply_short_channel_ids_end(peer, msg);
|
err = handle_reply_short_channel_ids_end(peer, msg);
|
||||||
goto handled_relay;
|
goto handled_relay;
|
||||||
case WIRE_OBS_ONION_MESSAGE:
|
|
||||||
err = handle_obs_onion_message(peer, msg);
|
|
||||||
goto handled_relay;
|
|
||||||
case WIRE_ONION_MESSAGE:
|
case WIRE_ONION_MESSAGE:
|
||||||
err = handle_onion_message(peer, msg);
|
err = handle_onion_message(peer, msg);
|
||||||
goto handled_relay;
|
goto handled_relay;
|
||||||
@ -1587,9 +1323,6 @@ static struct io_plan *recv_req(struct io_conn *conn,
|
|||||||
break;
|
break;
|
||||||
#endif /* !DEVELOPER */
|
#endif /* !DEVELOPER */
|
||||||
|
|
||||||
case WIRE_GOSSIPD_SEND_OBS_ONIONMSG:
|
|
||||||
return obs_onionmsg_req(conn, daemon, msg);
|
|
||||||
|
|
||||||
case WIRE_GOSSIPD_SEND_ONIONMSG:
|
case WIRE_GOSSIPD_SEND_ONIONMSG:
|
||||||
return onionmsg_req(conn, daemon, msg);
|
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_GET_TXOUT:
|
||||||
case WIRE_GOSSIPD_DEV_MEMLEAK_REPLY:
|
case WIRE_GOSSIPD_DEV_MEMLEAK_REPLY:
|
||||||
case WIRE_GOSSIPD_DEV_COMPACT_STORE_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_GOT_ONIONMSG_TO_US:
|
||||||
case WIRE_GOSSIPD_ADDGOSSIP_REPLY:
|
case WIRE_GOSSIPD_ADDGOSSIP_REPLY:
|
||||||
break;
|
break;
|
||||||
|
@ -74,22 +74,6 @@ msgdata,gossipd_dev_compact_store_reply,success,bool,
|
|||||||
msgtype,gossipd_new_blockheight,3026
|
msgtype,gossipd_new_blockheight,3026
|
||||||
msgdata,gossipd_new_blockheight,blockheight,u32,
|
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
|
msgtype,gossipd_got_onionmsg_to_us,3145
|
||||||
msgdata,gossipd_got_onionmsg_to_us,node_alias,pubkey,
|
msgdata,gossipd_got_onionmsg_to_us,node_alias,pubkey,
|
||||||
msgdata,gossipd_got_onionmsg_to_us,self_id,?secret,
|
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
|
msgdata,gossipd_got_onionmsg_to_us,rawmsg,u8,rawmsg_len
|
||||||
|
|
||||||
# Lightningd tells us to send a onion message.
|
# 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
|
msgtype,gossipd_send_onionmsg,3041
|
||||||
msgdata,gossipd_send_onionmsg,id,node_id,
|
msgdata,gossipd_send_onionmsg,id,node_id,
|
||||||
msgdata,gossipd_send_onionmsg,onion_len,u16,
|
msgdata,gossipd_send_onionmsg,onion_len,u16,
|
||||||
|
|
@ -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_COMPACT_STORE:
|
||||||
case WIRE_GOSSIPD_DEV_SET_TIME:
|
case WIRE_GOSSIPD_DEV_SET_TIME:
|
||||||
case WIRE_GOSSIPD_NEW_BLOCKHEIGHT:
|
case WIRE_GOSSIPD_NEW_BLOCKHEIGHT:
|
||||||
case WIRE_GOSSIPD_SEND_OBS_ONIONMSG:
|
|
||||||
case WIRE_GOSSIPD_SEND_ONIONMSG:
|
case WIRE_GOSSIPD_SEND_ONIONMSG:
|
||||||
case WIRE_GOSSIPD_ADDGOSSIP:
|
case WIRE_GOSSIPD_ADDGOSSIP:
|
||||||
/* This is a reply, so never gets through to here. */
|
/* 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:
|
case WIRE_GOSSIPD_ADDGOSSIP_REPLY:
|
||||||
break;
|
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:
|
case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US:
|
||||||
handle_onionmsg_to_us(gossip->ld, msg);
|
handle_onionmsg_to_us(gossip->ld, msg);
|
||||||
break;
|
break;
|
||||||
|
@ -15,15 +15,11 @@
|
|||||||
#include <sodium/randombytes.h>
|
#include <sodium/randombytes.h>
|
||||||
|
|
||||||
struct onion_message_hook_payload {
|
struct onion_message_hook_payload {
|
||||||
/* Pre-spec or modern? */
|
|
||||||
bool obsolete;
|
|
||||||
|
|
||||||
/* Optional */
|
/* Optional */
|
||||||
struct pubkey *blinding_in; /* obsolete only */
|
|
||||||
struct pubkey *reply_blinding;
|
struct pubkey *reply_blinding;
|
||||||
struct onionmsg_path **reply_path;
|
struct onionmsg_path **reply_path;
|
||||||
struct pubkey *reply_first_node; /* non-obsolete only */
|
struct pubkey *reply_first_node;
|
||||||
struct pubkey *our_alias; /* non-obsolete only */
|
struct pubkey *our_alias;
|
||||||
|
|
||||||
struct tlv_onionmsg_payload *om;
|
struct tlv_onionmsg_payload *om;
|
||||||
};
|
};
|
||||||
@ -53,34 +49,16 @@ static void onion_message_serialize(struct onion_message_hook_payload *payload,
|
|||||||
struct plugin *plugin)
|
struct plugin *plugin)
|
||||||
{
|
{
|
||||||
json_object_start(stream, "onion_message");
|
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)
|
if (payload->our_alias)
|
||||||
json_add_pubkey(stream, "our_alias", payload->our_alias);
|
json_add_pubkey(stream, "our_alias", payload->our_alias);
|
||||||
|
|
||||||
/* Modern style. */
|
|
||||||
if (payload->reply_first_node) {
|
if (payload->reply_first_node) {
|
||||||
json_add_blindedpath(stream, "reply_blindedpath",
|
json_add_blindedpath(stream, "reply_blindedpath",
|
||||||
payload->reply_blinding,
|
payload->reply_blinding,
|
||||||
payload->reply_first_node,
|
payload->reply_first_node,
|
||||||
payload->reply_path);
|
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 */
|
/* Common convenience fields */
|
||||||
if (payload->om->invoice_request)
|
if (payload->om->invoice_request)
|
||||||
json_add_hex_talarr(stream, "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
|
/* 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. */
|
* 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,
|
REGISTER_PLUGIN_HOOK(onion_message_blinded,
|
||||||
plugin_hook_continue,
|
plugin_hook_continue,
|
||||||
onion_message_hook_cb,
|
onion_message_hook_cb,
|
||||||
@ -135,96 +107,6 @@ REGISTER_PLUGIN_HOOK(onion_message_ourpath,
|
|||||||
onion_message_serialize,
|
onion_message_serialize,
|
||||||
struct onion_message_hook_payload *);
|
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)
|
void handle_onionmsg_to_us(struct lightningd *ld, const u8 *msg)
|
||||||
{
|
{
|
||||||
struct onion_message_hook_payload *payload;
|
struct onion_message_hook_payload *payload;
|
||||||
@ -233,15 +115,8 @@ void handle_onionmsg_to_us(struct lightningd *ld, const u8 *msg)
|
|||||||
size_t submsglen;
|
size_t submsglen;
|
||||||
const u8 *subptr;
|
const u8 *subptr;
|
||||||
|
|
||||||
#if DEVELOPER
|
|
||||||
if (ld->dev_ignore_modern_onion)
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
payload = tal(ld, struct onion_message_hook_payload);
|
payload = tal(ld, struct onion_message_hook_payload);
|
||||||
payload->obsolete = false;
|
|
||||||
payload->om = tlv_onionmsg_payload_new(payload);
|
payload->om = tlv_onionmsg_payload_new(payload);
|
||||||
payload->blinding_in = NULL;
|
|
||||||
payload->our_alias = tal(payload, struct pubkey);
|
payload->our_alias = tal(payload, struct pubkey);
|
||||||
|
|
||||||
if (!fromwire_gossipd_got_onionmsg_to_us(payload, msg,
|
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);
|
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 onion_hop {
|
||||||
struct pubkey node;
|
struct pubkey node;
|
||||||
u8 *tlv;
|
u8 *tlv;
|
||||||
|
@ -5,9 +5,6 @@
|
|||||||
|
|
||||||
struct lightningd;
|
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);
|
void handle_onionmsg_to_us(struct lightningd *ld, const u8 *msg);
|
||||||
|
|
||||||
#endif /* LIGHTNING_LIGHTNINGD_ONION_MESSAGE_H */
|
#endif /* LIGHTNING_LIGHTNINGD_ONION_MESSAGE_H */
|
||||||
|
@ -1286,7 +1286,6 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state)
|
|||||||
case WIRE_ANNOUNCEMENT_SIGNATURES:
|
case WIRE_ANNOUNCEMENT_SIGNATURES:
|
||||||
case WIRE_GOSSIP_TIMESTAMP_FILTER:
|
case WIRE_GOSSIP_TIMESTAMP_FILTER:
|
||||||
case WIRE_ONION_MESSAGE:
|
case WIRE_ONION_MESSAGE:
|
||||||
case WIRE_OBS_ONION_MESSAGE:
|
|
||||||
case WIRE_ACCEPT_CHANNEL2:
|
case WIRE_ACCEPT_CHANNEL2:
|
||||||
case WIRE_TX_ADD_INPUT:
|
case WIRE_TX_ADD_INPUT:
|
||||||
case WIRE_TX_REMOVE_INPUT:
|
case WIRE_TX_REMOVE_INPUT:
|
||||||
@ -1633,7 +1632,6 @@ static bool run_tx_interactive(struct state *state,
|
|||||||
case WIRE_ANNOUNCEMENT_SIGNATURES:
|
case WIRE_ANNOUNCEMENT_SIGNATURES:
|
||||||
case WIRE_GOSSIP_TIMESTAMP_FILTER:
|
case WIRE_GOSSIP_TIMESTAMP_FILTER:
|
||||||
case WIRE_ONION_MESSAGE:
|
case WIRE_ONION_MESSAGE:
|
||||||
case WIRE_OBS_ONION_MESSAGE:
|
|
||||||
case WIRE_TX_SIGNATURES:
|
case WIRE_TX_SIGNATURES:
|
||||||
case WIRE_OPEN_CHANNEL2:
|
case WIRE_OPEN_CHANNEL2:
|
||||||
case WIRE_ACCEPT_CHANNEL2:
|
case WIRE_ACCEPT_CHANNEL2:
|
||||||
@ -3687,7 +3685,6 @@ static u8 *handle_peer_in(struct state *state)
|
|||||||
case WIRE_ANNOUNCEMENT_SIGNATURES:
|
case WIRE_ANNOUNCEMENT_SIGNATURES:
|
||||||
case WIRE_GOSSIP_TIMESTAMP_FILTER:
|
case WIRE_GOSSIP_TIMESTAMP_FILTER:
|
||||||
case WIRE_ONION_MESSAGE:
|
case WIRE_ONION_MESSAGE:
|
||||||
case WIRE_OBS_ONION_MESSAGE:
|
|
||||||
case WIRE_ACCEPT_CHANNEL2:
|
case WIRE_ACCEPT_CHANNEL2:
|
||||||
case WIRE_TX_ADD_INPUT:
|
case WIRE_TX_ADD_INPUT:
|
||||||
case WIRE_TX_REMOVE_INPUT:
|
case WIRE_TX_REMOVE_INPUT:
|
||||||
|
@ -28,9 +28,7 @@ static LIST_HEAD(sent_list);
|
|||||||
struct sent {
|
struct sent {
|
||||||
/* We're in sent_invreqs, awaiting reply. */
|
/* We're in sent_invreqs, awaiting reply. */
|
||||||
struct list_node list;
|
struct list_node list;
|
||||||
/* The blinding factor used by reply (obsolete only) */
|
/* The alias used by reply */
|
||||||
struct pubkey *reply_blinding;
|
|
||||||
/* The alias used by reply (modern only) */
|
|
||||||
struct pubkey *reply_alias;
|
struct pubkey *reply_alias;
|
||||||
/* The command which sent us. */
|
/* The command which sent us. */
|
||||||
struct command *cmd;
|
struct command *cmd;
|
||||||
@ -49,17 +47,6 @@ struct sent {
|
|||||||
u32 wait_timeout;
|
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)
|
static struct sent *find_sent_by_alias(const struct pubkey *alias)
|
||||||
{
|
{
|
||||||
struct sent *i;
|
struct sent *i;
|
||||||
@ -443,48 +430,6 @@ static struct command_result *recv_modern_onion_message(struct command *cmd,
|
|||||||
return command_hook_success(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)
|
static void destroy_sent(struct sent *sent)
|
||||||
{
|
{
|
||||||
list_del(&sent->list);
|
list_del(&sent->list);
|
||||||
@ -681,7 +626,7 @@ static struct pubkey *path_to_node(const tal_t *ctx,
|
|||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Marshal arguments for sending obsolete and modern onion messages */
|
/* Marshal arguments for sending onion messages */
|
||||||
struct sending {
|
struct sending {
|
||||||
struct sent *sent;
|
struct sent *sent;
|
||||||
const char *msgfield;
|
const char *msgfield;
|
||||||
@ -692,63 +637,6 @@ struct sending {
|
|||||||
struct sent *sent);
|
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 *
|
static struct command_result *
|
||||||
send_modern_message(struct command *cmd,
|
send_modern_message(struct command *cmd,
|
||||||
struct tlv_onionmsg_payload_reply_path *reply_path,
|
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;
|
payloads[nhops-1]->reply_path = reply_path;
|
||||||
|
|
||||||
req = jsonrpc_request_start(cmd->plugin, cmd, "sendonionmessage",
|
req = jsonrpc_request_start(cmd->plugin, cmd, "sendonionmessage",
|
||||||
/* We try obsolete msg next */
|
sending->done,
|
||||||
send_obs_message,
|
|
||||||
forward_error,
|
forward_error,
|
||||||
sending);
|
sending->sent);
|
||||||
json_add_pubkey(req->js, "first_id", &sent->path[1]);
|
json_add_pubkey(req->js, "first_id", &sent->path[1]);
|
||||||
json_add_pubkey(req->js, "blinding", &fwd_blinding);
|
json_add_pubkey(req->js, "blinding", &fwd_blinding);
|
||||||
json_array_start(req->js, "hops");
|
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[] = {
|
static const struct plugin_hook hooks[] = {
|
||||||
{
|
|
||||||
"onion_message_blinded",
|
|
||||||
recv_obs_onion_message
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"onion_message_ourpath",
|
"onion_message_ourpath",
|
||||||
recv_modern_onion_message
|
recv_modern_onion_message
|
||||||
|
112
plugins/offers.c
112
plugins/offers.c
@ -41,11 +41,11 @@ static struct command_result *sendonionmessage_error(struct command *cmd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: replyfield string interface is to accomodate obsolete API */
|
/* FIXME: replyfield string interface is to accomodate obsolete API */
|
||||||
static struct command_result *
|
struct command_result *
|
||||||
send_modern_onion_reply(struct command *cmd,
|
send_onion_reply(struct command *cmd,
|
||||||
struct tlv_onionmsg_payload_reply_path *reply_path,
|
struct tlv_onionmsg_payload_reply_path *reply_path,
|
||||||
const char *replyfield,
|
const char *replyfield,
|
||||||
const u8 *replydata)
|
const u8 *replydata)
|
||||||
{
|
{
|
||||||
struct out_req *req;
|
struct out_req *req;
|
||||||
size_t nhops = tal_count(reply_path->path);
|
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);
|
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,
|
static struct command_result *onion_message_modern_call(struct command *cmd,
|
||||||
const char *buf,
|
const char *buf,
|
||||||
const jsmntok_t *params)
|
const jsmntok_t *params)
|
||||||
{
|
{
|
||||||
const jsmntok_t *om, *replytok, *invreqtok, *invtok;
|
const jsmntok_t *om, *replytok, *invreqtok, *invtok;
|
||||||
bool obsolete;
|
|
||||||
struct tlv_onionmsg_payload_reply_path *reply_path;
|
struct tlv_onionmsg_payload_reply_path *reply_path;
|
||||||
|
|
||||||
if (!offers_enabled)
|
if (!offers_enabled)
|
||||||
return command_hook_success(cmd);
|
return command_hook_success(cmd);
|
||||||
|
|
||||||
om = json_get_member(buf, params, "onion_message");
|
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");
|
replytok = json_get_member(buf, om, "reply_blindedpath");
|
||||||
if (replytok) {
|
if (replytok) {
|
||||||
reply_path = json_to_reply_path(cmd, buf, 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");
|
invreqtok = json_get_member(buf, om, "invoice_request");
|
||||||
if (invreqtok) {
|
if (invreqtok) {
|
||||||
|
const u8 *invreqbin = json_tok_bin_from_hex(tmpctx, buf, invreqtok);
|
||||||
if (reply_path)
|
if (reply_path)
|
||||||
return handle_invoice_request(cmd, buf,
|
return handle_invoice_request(cmd,
|
||||||
invreqtok,
|
invreqbin,
|
||||||
NULL, reply_path);
|
reply_path);
|
||||||
else
|
else
|
||||||
plugin_log(cmd->plugin, LOG_DBG,
|
plugin_log(cmd->plugin, LOG_DBG,
|
||||||
"invoice_request without reply_path");
|
"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");
|
invtok = json_get_member(buf, om, "invoice");
|
||||||
if (invtok) {
|
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);
|
return command_hook_success(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct plugin_hook hooks[] = {
|
static const struct plugin_hook hooks[] = {
|
||||||
{
|
|
||||||
"onion_message",
|
|
||||||
onion_message_call
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"onion_message_blinded",
|
"onion_message_blinded",
|
||||||
onion_message_modern_call
|
onion_message_modern_call
|
||||||
|
@ -9,11 +9,7 @@ struct command;
|
|||||||
/* Helper to send a reply */
|
/* Helper to send a reply */
|
||||||
struct command_result *WARN_UNUSED_RESULT
|
struct command_result *WARN_UNUSED_RESULT
|
||||||
send_onion_reply(struct command *cmd,
|
send_onion_reply(struct command *cmd,
|
||||||
/* Preferred */
|
|
||||||
struct tlv_onionmsg_payload_reply_path *reply_path,
|
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 char *replyfield,
|
||||||
const u8 *replydata);
|
const u8 *replydata);
|
||||||
#endif /* LIGHTNING_PLUGINS_OFFERS_H */
|
#endif /* LIGHTNING_PLUGINS_OFFERS_H */
|
||||||
|
@ -10,9 +10,7 @@
|
|||||||
struct inv {
|
struct inv {
|
||||||
struct tlv_invoice *inv;
|
struct tlv_invoice *inv;
|
||||||
|
|
||||||
const char *buf;
|
|
||||||
/* May be NULL */
|
/* May be NULL */
|
||||||
const jsmntok_t *replytok;
|
|
||||||
struct tlv_onionmsg_payload_reply_path *reply_path;
|
struct tlv_onionmsg_payload_reply_path *reply_path;
|
||||||
|
|
||||||
/* The offer, once we've looked it up. */
|
/* 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);
|
plugin_log(cmd->plugin, l, "%s", msg);
|
||||||
|
|
||||||
/* Only reply if they gave us a path */
|
/* Only reply if they gave us a path */
|
||||||
if (!inv->replytok && !inv->reply_path)
|
if (!inv->reply_path)
|
||||||
return command_hook_success(cmd);
|
return command_hook_success(cmd);
|
||||||
|
|
||||||
/* Don't send back internal error details. */
|
/* Don't send back internal error details. */
|
||||||
@ -55,8 +53,7 @@ fail_inv_level(struct command *cmd,
|
|||||||
|
|
||||||
errdata = tal_arr(cmd, u8, 0);
|
errdata = tal_arr(cmd, u8, 0);
|
||||||
towire_invoice_error(&errdata, err);
|
towire_invoice_error(&errdata, err);
|
||||||
return send_onion_reply(cmd, inv->reply_path, inv->buf, inv->replytok,
|
return send_onion_reply(cmd, inv->reply_path, "invoice_error", errdata);
|
||||||
"invoice_error", errdata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command_result *WARN_UNUSED_RESULT
|
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,
|
struct command_result *handle_invoice(struct command *cmd,
|
||||||
const char *buf,
|
const u8 *invbin,
|
||||||
const jsmntok_t *invtok,
|
struct tlv_onionmsg_payload_reply_path *reply_path STEALS)
|
||||||
const jsmntok_t *replytok,
|
|
||||||
struct tlv_onionmsg_payload_reply_path *reply_path)
|
|
||||||
{
|
{
|
||||||
const u8 *invbin = json_tok_bin_from_hex(cmd, buf, invtok);
|
|
||||||
size_t len = tal_count(invbin);
|
size_t len = tal_count(invbin);
|
||||||
struct inv *inv = tal(cmd, struct inv);
|
struct inv *inv = tal(cmd, struct inv);
|
||||||
struct out_req *req;
|
struct out_req *req;
|
||||||
@ -328,17 +322,7 @@ struct command_result *handle_invoice(struct command *cmd,
|
|||||||
int bad_feature;
|
int bad_feature;
|
||||||
struct sha256 m, shash;
|
struct sha256 m, shash;
|
||||||
|
|
||||||
if (reply_path) {
|
inv->reply_path = tal_steal(inv, 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->inv = tlv_invoice_new(cmd);
|
inv->inv = tlv_invoice_new(cmd);
|
||||||
if (!fromwire_invoice(&invbin, &len, inv->inv)) {
|
if (!fromwire_invoice(&invbin, &len, inv->inv)) {
|
||||||
|
@ -3,10 +3,8 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <plugins/libplugin.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,
|
struct command_result *handle_invoice(struct command *cmd,
|
||||||
const char *buf,
|
const u8 *invbin,
|
||||||
const jsmntok_t *invtok,
|
struct tlv_onionmsg_payload_reply_path *reply_path STEALS);
|
||||||
const jsmntok_t *replytok,
|
|
||||||
struct tlv_onionmsg_payload_reply_path *reply_path);
|
|
||||||
#endif /* LIGHTNING_PLUGINS_OFFERS_INV_HOOK_H */
|
#endif /* LIGHTNING_PLUGINS_OFFERS_INV_HOOK_H */
|
||||||
|
@ -15,10 +15,6 @@
|
|||||||
/* We need to keep the reply path around so we can reply with invoice */
|
/* We need to keep the reply path around so we can reply with invoice */
|
||||||
struct invreq {
|
struct invreq {
|
||||||
struct tlv_invoice_request *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;
|
struct tlv_onionmsg_payload_reply_path *reply_path;
|
||||||
|
|
||||||
/* The offer, once we've looked it up. */
|
/* The offer, once we've looked it up. */
|
||||||
@ -63,9 +59,7 @@ fail_invreq_level(struct command *cmd,
|
|||||||
|
|
||||||
errdata = tal_arr(cmd, u8, 0);
|
errdata = tal_arr(cmd, u8, 0);
|
||||||
towire_invoice_error(&errdata, err);
|
towire_invoice_error(&errdata, err);
|
||||||
return send_onion_reply(cmd, invreq->reply_path,
|
return send_onion_reply(cmd, invreq->reply_path, "invoice_error", errdata);
|
||||||
invreq->buf, invreq->replytok,
|
|
||||||
"invoice_error", errdata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command_result *WARN_UNUSED_RESULT PRINTF_FMT(3,4)
|
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));
|
json_tok_full(buf, t));
|
||||||
}
|
}
|
||||||
|
|
||||||
return send_onion_reply(cmd, ir->reply_path, ir->buf, ir->replytok,
|
return send_onion_reply(cmd, ir->reply_path, "invoice", rawinv);
|
||||||
"invoice", rawinv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command_result *createinvoice_error(struct command *cmd,
|
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,
|
struct command_result *handle_invoice_request(struct command *cmd,
|
||||||
const char *buf,
|
const u8 *invreqbin,
|
||||||
const jsmntok_t *invreqtok,
|
|
||||||
const jsmntok_t *replytok,
|
|
||||||
struct tlv_onionmsg_payload_reply_path *reply_path)
|
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);
|
size_t len = tal_count(invreqbin);
|
||||||
struct invreq *ir = tal(cmd, struct invreq);
|
struct invreq *ir = tal(cmd, struct invreq);
|
||||||
struct out_req *req;
|
struct out_req *req;
|
||||||
int bad_feature;
|
int bad_feature;
|
||||||
|
|
||||||
/* Make a copy of entire buffer, for later. */
|
ir->reply_path = tal_steal(ir, reply_path);
|
||||||
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->invreq = tlv_invoice_request_new(cmd);
|
ir->invreq = tlv_invoice_request_new(cmd);
|
||||||
if (!fromwire_invoice_request(&invreqbin, &len, ir->invreq)) {
|
if (!fromwire_invoice_request(&invreqbin, &len, ir->invreq)) {
|
||||||
|
@ -7,10 +7,6 @@ extern u32 cltv_final;
|
|||||||
|
|
||||||
/* We got an onionmessage with an invreq! */
|
/* We got an onionmessage with an invreq! */
|
||||||
struct command_result *handle_invoice_request(struct command *cmd,
|
struct command_result *handle_invoice_request(struct command *cmd,
|
||||||
const char *buf,
|
const u8 *invreqbin,
|
||||||
const jsmntok_t *invreqtok,
|
struct tlv_onionmsg_payload_reply_path *reply_path STEALS);
|
||||||
/* Obsolete onion */
|
|
||||||
const jsmntok_t *replytok,
|
|
||||||
/* Modern onion */
|
|
||||||
struct tlv_onionmsg_payload_reply_path *reply_path);
|
|
||||||
#endif /* LIGHTNING_PLUGINS_OFFERS_INVREQ_HOOK_H */
|
#endif /* LIGHTNING_PLUGINS_OFFERS_INVREQ_HOOK_H */
|
||||||
|
@ -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")
|
@pytest.mark.developer("needs --dev-force-privkey")
|
||||||
def test_getsharedsecret(node_factory):
|
def test_getsharedsecret(node_factory):
|
||||||
"""
|
"""
|
||||||
|
@ -3259,6 +3259,7 @@ def test_reject_invalid_payload(node_factory):
|
|||||||
l1.rpc.waitsendpay(inv['payment_hash'])
|
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")
|
@unittest.skipIf(not EXPERIMENTAL_FEATURES, "Needs blinding args to sendpay")
|
||||||
def test_sendpay_blinding(node_factory):
|
def test_sendpay_blinding(node_factory):
|
||||||
l1, l2, l3, l4 = node_factory.line_graph(4)
|
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']})
|
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):
|
def test_fetchinvoice(node_factory, bitcoind):
|
||||||
# We remove the conversion plugin on l3, causing it to get upset.
|
# We remove the conversion plugin on l3, causing it to get upset.
|
||||||
|
@ -1,30 +1,29 @@
|
|||||||
--- wire/extracted_onion_wire_csv 2020-03-25 10:24:12.861645774 +1030
|
--- wire/extracted_onion_wire_csv 2020-03-25 10:24:12.861645774 +1030
|
||||||
+++ - 2020-03-26 13:47:13.498294435 +1030
|
+++ - 2020-03-26 13:47:13.498294435 +1030
|
||||||
@@ -8,6 +8,31 @@
|
@@ -8,6 +8,30 @@
|
||||||
tlvtype,tlv_payload,payment_data,8
|
tlvtype,tlv_payload,payment_data,8
|
||||||
tlvdata,tlv_payload,payment_data,payment_secret,byte,32
|
tlvdata,tlv_payload,payment_data,payment_secret,byte,32
|
||||||
tlvdata,tlv_payload,payment_data,total_msat,tu64,
|
tlvdata,tlv_payload,payment_data,total_msat,tu64,
|
||||||
+tlvtype,onionmsg_payload,obs_next_node_id,4
|
+tlvtype,onionmsg_payload,reply_path,2
|
||||||
+tlvdata,onionmsg_payload,obs_next_node_id,node_id,point,
|
+tlvdata,onionmsg_payload,reply_path,first_node_id,point,
|
||||||
+tlvtype,onionmsg_payload,obs_next_short_channel_id,6
|
+tlvdata,onionmsg_payload,reply_path,blinding,point,
|
||||||
+tlvdata,onionmsg_payload,obs_next_short_channel_id,short_channel_id,short_channel_id,
|
+tlvdata,onionmsg_payload,reply_path,path,onionmsg_path,...
|
||||||
+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
|
+tlvtype,onionmsg_payload,enctlv,10
|
||||||
+tlvdata,onionmsg_payload,enctlv,enctlv,byte,...
|
+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
|
+tlvtype,onionmsg_payload,invoice_request,64
|
||||||
+tlvdata,onionmsg_payload,invoice_request,invoice_request,byte,...
|
+tlvdata,onionmsg_payload,invoice_request,invoice_request,byte,...
|
||||||
+tlvtype,onionmsg_payload,invoice,66
|
+tlvtype,onionmsg_payload,invoice,66
|
||||||
+tlvdata,onionmsg_payload,invoice,invoice,byte,...
|
+tlvdata,onionmsg_payload,invoice,invoice,byte,...
|
||||||
+tlvtype,onionmsg_payload,invoice_error,68
|
+tlvtype,onionmsg_payload,invoice_error,68
|
||||||
+tlvdata,onionmsg_payload,invoice_error,invoice_error,byte,...
|
+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
|
+tlvtype,encmsg_tlvs,next_node_id,4
|
||||||
+tlvdata,encmsg_tlvs,next_node_id,node_id,point,
|
+tlvdata,encmsg_tlvs,next_node_id,node_id,point,
|
||||||
+tlvtype,encmsg_tlvs,obs_next_short_channel_id,6
|
+tlvtype,encmsg_tlvs,next_blinding,12
|
||||||
+tlvdata,encmsg_tlvs,obs_next_short_channel_id,short_channel_id,short_channel_id,
|
+tlvdata,encmsg_tlvs,next_blinding,blinding,point,
|
||||||
|
+tlvtype,encmsg_tlvs,self_id,14
|
||||||
|
+tlvdata,encmsg_tlvs,self_id,data,byte,...
|
||||||
+subtype,onionmsg_path
|
+subtype,onionmsg_path
|
||||||
+subtypedata,onionmsg_path,node_id,point,
|
+subtypedata,onionmsg_path,node_id,point,
|
||||||
+subtypedata,onionmsg_path,enclen,u16,
|
+subtypedata,onionmsg_path,enclen,u16,
|
||||||
|
@ -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,
|
|
@ -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,
|
|
@ -1,9 +1,9 @@
|
|||||||
--- peer_wire.csv 2021-08-25 12:41:02.876254003 +0930
|
--- peer_wire.csv 2021-08-25 12:41:02.876254003 +0930
|
||||||
+++ peer_wire.csv.raw 2021-08-25 13:42:31.991693809 +0930
|
+++ peer_wire.csv.raw 2021-08-25 13:42:31.991693809 +0930
|
||||||
@@ -320,3 +210,7 @@
|
@@ -320,3 +210,7 @@
|
||||||
msgdata,obs_onion_message,obs_onion_message_tlvs,obs_onion_message_tlvs,
|
msgdata,gossip_timestamp_filter,chain_hash,chain_hash,
|
||||||
tlvtype,obs_onion_message_tlvs,blinding,2
|
msgdata,gossip_timestamp_filter,first_timestamp,u32,
|
||||||
tlvdata,obs_onion_message_tlvs,blinding,blinding,point,
|
msgdata,gossip_timestamp_filter,timestamp_range,u32,
|
||||||
+msgtype,onion_message,387,option_onion_messages
|
+msgtype,onion_message,387,option_onion_messages
|
||||||
+msgdata,onion_message,blinding,point,
|
+msgdata,onion_message,blinding,point,
|
||||||
+msgdata,onion_message,len,u16,
|
+msgdata,onion_message,len,u16,
|
||||||
|
@ -12,17 +12,8 @@ tlvtype,onionmsg_payload,reply_path,2
|
|||||||
tlvdata,onionmsg_payload,reply_path,first_node_id,point,
|
tlvdata,onionmsg_payload,reply_path,first_node_id,point,
|
||||||
tlvdata,onionmsg_payload,reply_path,blinding,point,
|
tlvdata,onionmsg_payload,reply_path,blinding,point,
|
||||||
tlvdata,onionmsg_payload,reply_path,path,onionmsg_path,...
|
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
|
tlvtype,onionmsg_payload,enctlv,10
|
||||||
tlvdata,onionmsg_payload,enctlv,enctlv,byte,...
|
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
|
tlvtype,onionmsg_payload,invoice_request,64
|
||||||
tlvdata,onionmsg_payload,invoice_request,invoice_request,byte,...
|
tlvdata,onionmsg_payload,invoice_request,invoice_request,byte,...
|
||||||
tlvtype,onionmsg_payload,invoice,66
|
tlvtype,onionmsg_payload,invoice,66
|
||||||
@ -33,8 +24,6 @@ tlvtype,encmsg_tlvs,padding,1
|
|||||||
tlvdata,encmsg_tlvs,padding,pad,byte,...
|
tlvdata,encmsg_tlvs,padding,pad,byte,...
|
||||||
tlvtype,encmsg_tlvs,next_node_id,4
|
tlvtype,encmsg_tlvs,next_node_id,4
|
||||||
tlvdata,encmsg_tlvs,next_node_id,node_id,point,
|
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
|
tlvtype,encmsg_tlvs,next_blinding,12
|
||||||
tlvdata,encmsg_tlvs,next_blinding,blinding,point,
|
tlvdata,encmsg_tlvs,next_blinding,blinding,point,
|
||||||
tlvtype,encmsg_tlvs,self_id,14
|
tlvtype,encmsg_tlvs,self_id,14
|
||||||
|
|
@ -34,7 +34,6 @@ static bool unknown_type(enum peer_wire t)
|
|||||||
case WIRE_REPLY_CHANNEL_RANGE:
|
case WIRE_REPLY_CHANNEL_RANGE:
|
||||||
case WIRE_GOSSIP_TIMESTAMP_FILTER:
|
case WIRE_GOSSIP_TIMESTAMP_FILTER:
|
||||||
case WIRE_ONION_MESSAGE:
|
case WIRE_ONION_MESSAGE:
|
||||||
case WIRE_OBS_ONION_MESSAGE:
|
|
||||||
case WIRE_TX_ADD_INPUT:
|
case WIRE_TX_ADD_INPUT:
|
||||||
case WIRE_TX_REMOVE_INPUT:
|
case WIRE_TX_REMOVE_INPUT:
|
||||||
case WIRE_TX_ADD_OUTPUT:
|
case WIRE_TX_ADD_OUTPUT:
|
||||||
@ -64,7 +63,6 @@ bool is_msg_for_gossipd(const u8 *cursor)
|
|||||||
case WIRE_QUERY_CHANNEL_RANGE:
|
case WIRE_QUERY_CHANNEL_RANGE:
|
||||||
case WIRE_REPLY_CHANNEL_RANGE:
|
case WIRE_REPLY_CHANNEL_RANGE:
|
||||||
case WIRE_ONION_MESSAGE:
|
case WIRE_ONION_MESSAGE:
|
||||||
case WIRE_OBS_ONION_MESSAGE:
|
|
||||||
return true;
|
return true;
|
||||||
case WIRE_WARNING:
|
case WIRE_WARNING:
|
||||||
case WIRE_INIT:
|
case WIRE_INIT:
|
||||||
|
@ -328,12 +328,6 @@ msgtype,gossip_timestamp_filter,265,gossip_queries
|
|||||||
msgdata,gossip_timestamp_filter,chain_hash,chain_hash,
|
msgdata,gossip_timestamp_filter,chain_hash,chain_hash,
|
||||||
msgdata,gossip_timestamp_filter,first_timestamp,u32,
|
msgdata,gossip_timestamp_filter,first_timestamp,u32,
|
||||||
msgdata,gossip_timestamp_filter,timestamp_range,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
|
msgtype,onion_message,387,option_onion_messages
|
||||||
msgdata,onion_message,blinding,point,
|
msgdata,onion_message,blinding,point,
|
||||||
msgdata,onion_message,len,u16,
|
msgdata,onion_message,len,u16,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user