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_ERROR:
|
||||
case WIRE_ONION_MESSAGE:
|
||||
case WIRE_OBS_ONION_MESSAGE:
|
||||
abort();
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
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 */
|
||||
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
|
||||
|
@ -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 */
|
||||
|
@ -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)) {
|
||||
|
@ -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 */
|
||||
|
@ -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)) {
|
||||
|
@ -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 */
|
||||
|
@ -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):
|
||||
"""
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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.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,
|
||||
|
@ -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
|
||||
|
|
@ -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:
|
||||
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue
Block a user