mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 15:14:23 +01:00
connectd: restore obs2 onion support.
I removed these prematurely: we *haven't* had a release since
introducing them!
This consists of reverting d15d629b8b
"plugins/fetchinvoice: remove obsolete string-based API." and
plugins/fetchinvoice: remove obsolete string-based
API. "onion_messages: remove obs2 support."
Some minor changes due to updated fromwire_tlv API since they
were removed, but not much.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-EXPERIMENTAL: REVERT: Removed backwards compat with onion messages from v0.10.1.
This commit is contained in:
@@ -114,6 +114,19 @@ static u8 *enctlv_from_encmsg_raw(const tal_t *ctx,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u8 *enctlv_from_obs2_encmsg(const tal_t *ctx,
|
||||||
|
const struct privkey *blinding,
|
||||||
|
const struct pubkey *node,
|
||||||
|
const struct tlv_obs2_encmsg_tlvs *encmsg,
|
||||||
|
struct privkey *next_blinding,
|
||||||
|
struct pubkey *node_alias)
|
||||||
|
{
|
||||||
|
u8 *encmsg_raw = tal_arr(NULL, u8, 0);
|
||||||
|
towire_tlv_obs2_encmsg_tlvs(&encmsg_raw, encmsg);
|
||||||
|
return enctlv_from_encmsg_raw(ctx, blinding, node, take(encmsg_raw),
|
||||||
|
next_blinding, node_alias);
|
||||||
|
}
|
||||||
|
|
||||||
static u8 *enctlv_from_encmsg(const tal_t *ctx,
|
static u8 *enctlv_from_encmsg(const tal_t *ctx,
|
||||||
const struct privkey *blinding,
|
const struct privkey *blinding,
|
||||||
const struct pubkey *node,
|
const struct pubkey *node,
|
||||||
@@ -183,6 +196,22 @@ static u8 *decrypt_encmsg_raw(const tal_t *ctx,
|
|||||||
return dec;
|
return dec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct tlv_obs2_encmsg_tlvs *decrypt_obs2_encmsg(const tal_t *ctx,
|
||||||
|
const struct pubkey *blinding,
|
||||||
|
const struct secret *ss,
|
||||||
|
const u8 *enctlv)
|
||||||
|
{
|
||||||
|
const u8 *cursor = decrypt_encmsg_raw(tmpctx, blinding, ss, enctlv);
|
||||||
|
size_t maxlen = tal_bytelen(cursor);
|
||||||
|
|
||||||
|
/* BOLT-onion-message #4:
|
||||||
|
*
|
||||||
|
* - if the `enctlv` is not a valid TLV...
|
||||||
|
* - MUST drop the message.
|
||||||
|
*/
|
||||||
|
return fromwire_tlv_obs2_encmsg_tlvs(ctx, &cursor, &maxlen);
|
||||||
|
}
|
||||||
|
|
||||||
static struct tlv_encrypted_data_tlv *decrypt_encmsg(const tal_t *ctx,
|
static struct tlv_encrypted_data_tlv *decrypt_encmsg(const tal_t *ctx,
|
||||||
const struct pubkey *blinding,
|
const struct pubkey *blinding,
|
||||||
const struct secret *ss,
|
const struct secret *ss,
|
||||||
@@ -325,3 +354,131 @@ u8 *create_final_enctlv(const tal_t *ctx,
|
|||||||
return enctlv_from_encmsg(ctx, blinding, final_node, encmsg,
|
return enctlv_from_encmsg(ctx, blinding, final_node, encmsg,
|
||||||
&unused_next_blinding, node_alias);
|
&unused_next_blinding, node_alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Obsolete variants */
|
||||||
|
bool decrypt_obs2_enctlv(const struct pubkey *blinding,
|
||||||
|
const struct secret *ss,
|
||||||
|
const u8 *enctlv,
|
||||||
|
struct pubkey *next_node,
|
||||||
|
struct pubkey *next_blinding)
|
||||||
|
{
|
||||||
|
struct tlv_obs2_encmsg_tlvs *encmsg;
|
||||||
|
|
||||||
|
encmsg = decrypt_obs2_encmsg(tmpctx, blinding, ss, enctlv);
|
||||||
|
if (!encmsg)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* BOLT-onion-message #4:
|
||||||
|
*
|
||||||
|
* The reader:
|
||||||
|
* - if it is not the final node according to the onion encryption:
|
||||||
|
*...
|
||||||
|
* - if the `enctlv` ... does not contain
|
||||||
|
* `next_node_id`:
|
||||||
|
* - MUST drop the message.
|
||||||
|
*/
|
||||||
|
if (!encmsg->next_node_id)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* BOLT-onion-message #4:
|
||||||
|
* The reader:
|
||||||
|
* - if it is not the final node according to the onion encryption:
|
||||||
|
*...
|
||||||
|
* - if the `enctlv` contains `self_id`:
|
||||||
|
* - MUST drop the message.
|
||||||
|
*/
|
||||||
|
if (encmsg->self_id)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* BOLT-onion-message #4:
|
||||||
|
* The reader:
|
||||||
|
* - if it is not the final node according to the onion encryption:
|
||||||
|
*...
|
||||||
|
* - if `blinding` is specified in the `enctlv`:
|
||||||
|
* - MUST pass that as `blinding` in the `onion_message`
|
||||||
|
* - otherwise:
|
||||||
|
* - MUST pass `blinding` derived as in
|
||||||
|
* [Route Blinding][route-blinding] (i.e.
|
||||||
|
* `E(i+1) = H(E(i) || ss(i)) * E(i)`).
|
||||||
|
*/
|
||||||
|
*next_node = *encmsg->next_node_id;
|
||||||
|
if (encmsg->next_blinding)
|
||||||
|
*next_blinding = *encmsg->next_blinding;
|
||||||
|
else {
|
||||||
|
/* E(i-1) = H(E(i) || ss(i)) * E(i) */
|
||||||
|
struct sha256 h;
|
||||||
|
blinding_hash_e_and_ss(blinding, ss, &h);
|
||||||
|
blinding_next_pubkey(blinding, &h, next_blinding);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool decrypt_obs2_final_enctlv(const tal_t *ctx,
|
||||||
|
const struct pubkey *blinding,
|
||||||
|
const struct secret *ss,
|
||||||
|
const u8 *enctlv,
|
||||||
|
const struct pubkey *my_id,
|
||||||
|
struct pubkey *alias,
|
||||||
|
struct secret **self_id)
|
||||||
|
{
|
||||||
|
struct tlv_obs2_encmsg_tlvs *encmsg;
|
||||||
|
struct secret node_id_blinding;
|
||||||
|
|
||||||
|
/* Repeat the tweak to get the alias it was using for us */
|
||||||
|
subkey_from_hmac("blinded_node_id", ss, &node_id_blinding);
|
||||||
|
*alias = *my_id;
|
||||||
|
if (secp256k1_ec_pubkey_tweak_mul(secp256k1_ctx,
|
||||||
|
&alias->pubkey,
|
||||||
|
node_id_blinding.data) != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
encmsg = decrypt_obs2_encmsg(tmpctx, blinding, ss, enctlv);
|
||||||
|
if (!encmsg)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (tal_bytelen(encmsg->self_id) == sizeof(**self_id)) {
|
||||||
|
*self_id = tal(ctx, struct secret);
|
||||||
|
memcpy(*self_id, encmsg->self_id, sizeof(**self_id));
|
||||||
|
} else
|
||||||
|
*self_id = NULL;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 *create_obs2_enctlv(const tal_t *ctx,
|
||||||
|
const struct privkey *blinding,
|
||||||
|
const struct pubkey *node,
|
||||||
|
const struct pubkey *next_node,
|
||||||
|
size_t padlen,
|
||||||
|
const struct pubkey *override_blinding,
|
||||||
|
struct privkey *next_blinding,
|
||||||
|
struct pubkey *node_alias)
|
||||||
|
{
|
||||||
|
struct tlv_obs2_encmsg_tlvs *encmsg = tlv_obs2_encmsg_tlvs_new(tmpctx);
|
||||||
|
if (padlen)
|
||||||
|
encmsg->padding = tal_arrz(encmsg, u8, padlen);
|
||||||
|
encmsg->next_node_id = cast_const(struct pubkey *, next_node);
|
||||||
|
encmsg->next_blinding = cast_const(struct pubkey *, override_blinding);
|
||||||
|
|
||||||
|
return enctlv_from_obs2_encmsg(ctx, blinding, node, encmsg,
|
||||||
|
next_blinding, node_alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 *create_obs2_final_enctlv(const tal_t *ctx,
|
||||||
|
const struct privkey *blinding,
|
||||||
|
const struct pubkey *final_node,
|
||||||
|
size_t padlen,
|
||||||
|
const struct secret *self_id,
|
||||||
|
struct pubkey *node_alias)
|
||||||
|
{
|
||||||
|
struct tlv_obs2_encmsg_tlvs *encmsg = tlv_obs2_encmsg_tlvs_new(tmpctx);
|
||||||
|
struct privkey unused_next_blinding;
|
||||||
|
|
||||||
|
if (padlen)
|
||||||
|
encmsg->padding = tal_arrz(encmsg, u8, padlen);
|
||||||
|
if (self_id)
|
||||||
|
encmsg->self_id = (u8 *)tal_dup(encmsg, struct secret, self_id);
|
||||||
|
|
||||||
|
return enctlv_from_obs2_encmsg(ctx, blinding, final_node, encmsg,
|
||||||
|
&unused_next_blinding, node_alias);
|
||||||
|
}
|
||||||
|
|||||||
@@ -105,4 +105,36 @@ bool decrypt_final_enctlv(const tal_t *ctx,
|
|||||||
struct secret **path_id)
|
struct secret **path_id)
|
||||||
NON_NULL_ARGS(1, 2, 4, 5);
|
NON_NULL_ARGS(1, 2, 4, 5);
|
||||||
|
|
||||||
|
/* Obsolete variants */
|
||||||
|
u8 *create_obs2_enctlv(const tal_t *ctx,
|
||||||
|
const struct privkey *blinding,
|
||||||
|
const struct pubkey *node,
|
||||||
|
const struct pubkey *next_node,
|
||||||
|
size_t padlen,
|
||||||
|
const struct pubkey *override_blinding,
|
||||||
|
struct privkey *next_blinding,
|
||||||
|
struct pubkey *node_alias)
|
||||||
|
NON_NULL_ARGS(2, 3, 4, 7, 8);
|
||||||
|
u8 *create_obs2_final_enctlv(const tal_t *ctx,
|
||||||
|
const struct privkey *blinding,
|
||||||
|
const struct pubkey *final_node,
|
||||||
|
size_t padlen,
|
||||||
|
const struct secret *self_id,
|
||||||
|
struct pubkey *node_alias)
|
||||||
|
NON_NULL_ARGS(2, 3, 6);
|
||||||
|
bool decrypt_obs2_enctlv(const struct pubkey *blinding,
|
||||||
|
const struct secret *ss,
|
||||||
|
const u8 *enctlv,
|
||||||
|
struct pubkey *next_node,
|
||||||
|
struct pubkey *next_blinding)
|
||||||
|
NON_NULL_ARGS(1, 2, 4, 5);
|
||||||
|
bool decrypt_obs2_final_enctlv(const tal_t *ctx,
|
||||||
|
const struct pubkey *blinding,
|
||||||
|
const struct secret *ss,
|
||||||
|
const u8 *enctlv,
|
||||||
|
const struct pubkey *my_id,
|
||||||
|
struct pubkey *alias,
|
||||||
|
struct secret **self_id)
|
||||||
|
NON_NULL_ARGS(1, 2, 4, 5);
|
||||||
|
|
||||||
#endif /* LIGHTNING_COMMON_BLINDEDPATH_H */
|
#endif /* LIGHTNING_COMMON_BLINDEDPATH_H */
|
||||||
|
|||||||
@@ -158,6 +158,42 @@ struct wally_psbt *json_to_psbt(const tal_t *ctx, const char *buffer,
|
|||||||
return psbt_from_b64(ctx, buffer + tok->start, tok->end - tok->start);
|
return psbt_from_b64(ctx, buffer + tok->start, tok->end - tok->start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct tlv_obs2_onionmsg_payload_reply_path *
|
||||||
|
json_to_obs2_reply_path(const tal_t *ctx, const char *buffer, const jsmntok_t *tok)
|
||||||
|
{
|
||||||
|
struct tlv_obs2_onionmsg_payload_reply_path *rpath;
|
||||||
|
const jsmntok_t *hops, *t;
|
||||||
|
size_t i;
|
||||||
|
const char *err;
|
||||||
|
|
||||||
|
rpath = tal(ctx, struct tlv_obs2_onionmsg_payload_reply_path);
|
||||||
|
err = json_scan(tmpctx, buffer, tok, "{blinding:%,first_node_id:%}",
|
||||||
|
JSON_SCAN(json_to_pubkey, &rpath->blinding),
|
||||||
|
JSON_SCAN(json_to_pubkey, &rpath->first_node_id),
|
||||||
|
NULL);
|
||||||
|
if (err)
|
||||||
|
return tal_free(rpath);
|
||||||
|
|
||||||
|
hops = json_get_member(buffer, tok, "hops");
|
||||||
|
if (!hops || hops->size < 1)
|
||||||
|
return tal_free(rpath);
|
||||||
|
|
||||||
|
rpath->path = tal_arr(rpath, struct onionmsg_path *, hops->size);
|
||||||
|
json_for_each_arr(i, t, hops) {
|
||||||
|
rpath->path[i] = tal(rpath->path, struct onionmsg_path);
|
||||||
|
err = json_scan(tmpctx, buffer, t, "{id:%,encrypted_recipient_data:%}",
|
||||||
|
JSON_SCAN(json_to_pubkey,
|
||||||
|
&rpath->path[i]->node_id),
|
||||||
|
JSON_SCAN_TAL(rpath->path[i],
|
||||||
|
json_tok_bin_from_hex,
|
||||||
|
&rpath->path[i]->encrypted_recipient_data));
|
||||||
|
if (err)
|
||||||
|
return tal_free(rpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rpath;
|
||||||
|
}
|
||||||
|
|
||||||
struct tlv_onionmsg_payload_reply_path *
|
struct tlv_onionmsg_payload_reply_path *
|
||||||
json_to_reply_path(const tal_t *ctx, const char *buffer, const jsmntok_t *tok)
|
json_to_reply_path(const tal_t *ctx, const char *buffer, const jsmntok_t *tok)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -88,6 +88,10 @@ bool split_tok(const char *buffer, const jsmntok_t *tok,
|
|||||||
struct tlv_onionmsg_payload_reply_path *
|
struct tlv_onionmsg_payload_reply_path *
|
||||||
json_to_reply_path(const tal_t *ctx, const char *buffer, const jsmntok_t *tok);
|
json_to_reply_path(const tal_t *ctx, const char *buffer, const jsmntok_t *tok);
|
||||||
|
|
||||||
|
/* Obsolete version! */
|
||||||
|
struct tlv_obs2_onionmsg_payload_reply_path *
|
||||||
|
json_to_obs2_reply_path(const tal_t *ctx, const char *buffer, const jsmntok_t *tok);
|
||||||
|
|
||||||
/* Helpers for outputting JSON results */
|
/* Helpers for outputting JSON results */
|
||||||
|
|
||||||
/* '"fieldname" : "0289abcdef..."' or "0289abcdef..." if fieldname is NULL */
|
/* '"fieldname" : "0289abcdef..."' or "0289abcdef..." if fieldname is NULL */
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ msgdata,connectd_ping_reply,totlen,u16,
|
|||||||
|
|
||||||
# We tell lightningd we got an onionmsg
|
# We tell lightningd we got an onionmsg
|
||||||
msgtype,connectd_got_onionmsg_to_us,2145
|
msgtype,connectd_got_onionmsg_to_us,2145
|
||||||
|
msgdata,connectd_got_onionmsg_to_us,obs2,bool,
|
||||||
msgdata,connectd_got_onionmsg_to_us,node_alias,pubkey,
|
msgdata,connectd_got_onionmsg_to_us,node_alias,pubkey,
|
||||||
msgdata,connectd_got_onionmsg_to_us,self_id,?secret,
|
msgdata,connectd_got_onionmsg_to_us,self_id,?secret,
|
||||||
msgdata,connectd_got_onionmsg_to_us,reply_blinding,?pubkey,
|
msgdata,connectd_got_onionmsg_to_us,reply_blinding,?pubkey,
|
||||||
@@ -133,6 +134,7 @@ msgdata,connectd_got_onionmsg_to_us,rawmsg,u8,rawmsg_len
|
|||||||
|
|
||||||
# Lightningd tells us to send an onion message.
|
# Lightningd tells us to send an onion message.
|
||||||
msgtype,connectd_send_onionmsg,2041
|
msgtype,connectd_send_onionmsg,2041
|
||||||
|
msgdata,connectd_send_onionmsg,obs2,bool,
|
||||||
msgdata,connectd_send_onionmsg,id,node_id,
|
msgdata,connectd_send_onionmsg,id,node_id,
|
||||||
msgdata,connectd_send_onionmsg,onion_len,u16,
|
msgdata,connectd_send_onionmsg,onion_len,u16,
|
||||||
msgdata,connectd_send_onionmsg,onion,u8,onion_len
|
msgdata,connectd_send_onionmsg,onion,u8,onion_len
|
||||||
|
|||||||
|
@@ -633,6 +633,9 @@ static bool handle_message_locally(struct peer *peer, const u8 *msg)
|
|||||||
} else if (type == WIRE_PONG) {
|
} else if (type == WIRE_PONG) {
|
||||||
handle_pong_in(peer, msg);
|
handle_pong_in(peer, msg);
|
||||||
return true;
|
return true;
|
||||||
|
} else if (type == WIRE_OBS2_ONION_MESSAGE) {
|
||||||
|
handle_obs2_onion_message(peer->daemon, peer, msg);
|
||||||
|
return true;
|
||||||
} else if (type == WIRE_ONION_MESSAGE) {
|
} else if (type == WIRE_ONION_MESSAGE) {
|
||||||
handle_onion_message(peer->daemon, peer, msg);
|
handle_onion_message(peer->daemon, peer, msg);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -16,21 +16,178 @@
|
|||||||
#include <connectd/onion_message.h>
|
#include <connectd/onion_message.h>
|
||||||
#include <wire/peer_wire.h>
|
#include <wire/peer_wire.h>
|
||||||
|
|
||||||
|
/* Peer sends obsolete onion msg. */
|
||||||
|
void handle_obs2_onion_message(struct daemon *daemon,
|
||||||
|
struct peer *peer, const u8 *msg)
|
||||||
|
{
|
||||||
|
enum onion_wire badreason;
|
||||||
|
struct onionpacket *op;
|
||||||
|
struct pubkey blinding, ephemeral;
|
||||||
|
struct route_step *rs;
|
||||||
|
u8 *onion;
|
||||||
|
struct tlv_obs2_onionmsg_payload *om;
|
||||||
|
struct secret ss, onion_ss;
|
||||||
|
const u8 *cursor;
|
||||||
|
size_t max, maxlen;
|
||||||
|
|
||||||
|
/* Ignore unless explicitly turned on. */
|
||||||
|
if (!feature_offered(daemon->our_features->bits[NODE_ANNOUNCE_FEATURE],
|
||||||
|
OPT_ONION_MESSAGES))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* FIXME: ratelimit! */
|
||||||
|
if (!fromwire_obs2_onion_message(msg, msg, &blinding, &onion)) {
|
||||||
|
inject_peer_msg(peer,
|
||||||
|
towire_warningfmt(NULL, NULL,
|
||||||
|
"Bad onion_message"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We unwrap the onion now. */
|
||||||
|
op = parse_onionpacket(tmpctx, onion, tal_bytelen(onion), &badreason);
|
||||||
|
if (!op) {
|
||||||
|
status_peer_debug(&peer->id, "onion msg: can't parse onionpacket: %s",
|
||||||
|
onion_wire_name(badreason));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ephemeral = op->ephemeralkey;
|
||||||
|
if (!unblind_onion(&blinding, ecdh, &ephemeral, &ss)) {
|
||||||
|
status_peer_debug(&peer->id, "onion msg: can't unblind onionpacket");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now get onion shared secret and parse it. */
|
||||||
|
ecdh(&ephemeral, &onion_ss);
|
||||||
|
rs = process_onionpacket(tmpctx, op, &onion_ss, NULL, 0, false);
|
||||||
|
if (!rs) {
|
||||||
|
status_peer_debug(&peer->id,
|
||||||
|
"onion msg: can't process onionpacket ss=%s",
|
||||||
|
type_to_string(tmpctx, struct secret, &onion_ss));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The raw payload is prepended with length in the modern onion. */
|
||||||
|
cursor = rs->raw_payload;
|
||||||
|
max = tal_bytelen(rs->raw_payload);
|
||||||
|
maxlen = fromwire_bigsize(&cursor, &max);
|
||||||
|
if (!cursor) {
|
||||||
|
status_peer_debug(&peer->id, "onion msg: Invalid hop payload %s",
|
||||||
|
tal_hex(tmpctx, rs->raw_payload));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (maxlen > max) {
|
||||||
|
status_peer_debug(&peer->id, "onion msg: overlong hop payload %s",
|
||||||
|
tal_hex(tmpctx, rs->raw_payload));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
om = fromwire_tlv_obs2_onionmsg_payload(msg, &cursor, &maxlen);
|
||||||
|
if (!om) {
|
||||||
|
status_peer_debug(&peer->id, "onion msg: invalid onionmsg_payload %s",
|
||||||
|
tal_hex(tmpctx, rs->raw_payload));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rs->nextcase == ONION_END) {
|
||||||
|
struct pubkey *reply_blinding, *first_node_id, me, alias;
|
||||||
|
const struct onionmsg_path **reply_path;
|
||||||
|
struct secret *self_id;
|
||||||
|
u8 *omsg;
|
||||||
|
|
||||||
|
if (!pubkey_from_node_id(&me, &daemon->id)) {
|
||||||
|
status_broken("Failed to convert own id");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Final enctlv is actually optional */
|
||||||
|
if (!om->enctlv) {
|
||||||
|
alias = me;
|
||||||
|
self_id = NULL;
|
||||||
|
} else if (!decrypt_obs2_final_enctlv(tmpctx, &blinding, &ss,
|
||||||
|
om->enctlv, &me, &alias,
|
||||||
|
&self_id)) {
|
||||||
|
status_peer_debug(&peer->id,
|
||||||
|
"onion msg: failed to decrypt enctlv"
|
||||||
|
" %s", tal_hex(tmpctx, om->enctlv));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (om->reply_path) {
|
||||||
|
first_node_id = &om->reply_path->first_node_id;
|
||||||
|
reply_blinding = &om->reply_path->blinding;
|
||||||
|
reply_path = cast_const2(const struct onionmsg_path **,
|
||||||
|
om->reply_path->path);
|
||||||
|
} else {
|
||||||
|
first_node_id = NULL;
|
||||||
|
reply_blinding = NULL;
|
||||||
|
reply_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(daemon->master,
|
||||||
|
take(towire_connectd_got_onionmsg_to_us(NULL,
|
||||||
|
true, /* obs2 */
|
||||||
|
&alias, self_id,
|
||||||
|
reply_blinding,
|
||||||
|
first_node_id,
|
||||||
|
reply_path,
|
||||||
|
omsg)));
|
||||||
|
} else {
|
||||||
|
struct pubkey next_node, next_blinding;
|
||||||
|
struct peer *next_peer;
|
||||||
|
struct node_id next_node_id;
|
||||||
|
|
||||||
|
/* This fails as expected if no enctlv. */
|
||||||
|
if (!decrypt_obs2_enctlv(&blinding, &ss, om->enctlv, &next_node,
|
||||||
|
&next_blinding)) {
|
||||||
|
status_peer_debug(&peer->id,
|
||||||
|
"onion msg: invalid enctlv %s",
|
||||||
|
tal_hex(tmpctx, om->enctlv));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Even though lightningd checks for valid ids, there's a race
|
||||||
|
* where it might vanish before we read this command. */
|
||||||
|
node_id_from_pubkey(&next_node_id, &next_node);
|
||||||
|
next_peer = peer_htable_get(&daemon->peers, &next_node_id);
|
||||||
|
if (!next_peer) {
|
||||||
|
status_peer_debug(&peer->id,
|
||||||
|
"onion msg: unknown next peer %s",
|
||||||
|
type_to_string(tmpctx,
|
||||||
|
struct pubkey,
|
||||||
|
&next_node));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
inject_peer_msg(next_peer,
|
||||||
|
take(towire_obs2_onion_message(NULL,
|
||||||
|
&next_blinding,
|
||||||
|
serialize_onionpacket(tmpctx, rs->next))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void onionmsg_req(struct daemon *daemon, const u8 *msg)
|
void onionmsg_req(struct daemon *daemon, const u8 *msg)
|
||||||
{
|
{
|
||||||
struct node_id id;
|
struct node_id id;
|
||||||
u8 *onionmsg;
|
u8 *onionmsg;
|
||||||
struct pubkey blinding;
|
struct pubkey blinding;
|
||||||
struct peer *peer;
|
struct peer *peer;
|
||||||
|
bool obs2;
|
||||||
|
|
||||||
if (!fromwire_connectd_send_onionmsg(msg, msg, &id, &onionmsg, &blinding))
|
if (!fromwire_connectd_send_onionmsg(msg, msg, &obs2, &id, &onionmsg, &blinding))
|
||||||
master_badmsg(WIRE_CONNECTD_SEND_ONIONMSG, msg);
|
master_badmsg(WIRE_CONNECTD_SEND_ONIONMSG, msg);
|
||||||
|
|
||||||
/* Even though lightningd checks for valid ids, there's a race
|
/* Even though lightningd checks for valid ids, there's a race
|
||||||
* where it might vanish before we read this command. */
|
* where it might vanish before we read this command. */
|
||||||
peer = peer_htable_get(&daemon->peers, &id);
|
peer = peer_htable_get(&daemon->peers, &id);
|
||||||
if (peer) {
|
if (peer) {
|
||||||
u8 *omsg = towire_onion_message(NULL, &blinding, onionmsg);
|
u8 *omsg;
|
||||||
|
if (obs2)
|
||||||
|
omsg = towire_obs2_onion_message(NULL, &blinding, onionmsg);
|
||||||
|
else
|
||||||
|
omsg = towire_onion_message(NULL, &blinding, onionmsg);
|
||||||
inject_peer_msg(peer, take(omsg));
|
inject_peer_msg(peer, take(omsg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,6 +305,7 @@ void handle_onion_message(struct daemon *daemon,
|
|||||||
towire_tlvstream_raw(&omsg, om->fields);
|
towire_tlvstream_raw(&omsg, om->fields);
|
||||||
daemon_conn_send(daemon->master,
|
daemon_conn_send(daemon->master,
|
||||||
take(towire_connectd_got_onionmsg_to_us(NULL,
|
take(towire_connectd_got_onionmsg_to_us(NULL,
|
||||||
|
false, /* !obs2 */
|
||||||
&alias, self_id,
|
&alias, self_id,
|
||||||
reply_blinding,
|
reply_blinding,
|
||||||
first_node_id,
|
first_node_id,
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <ccan/short_types/short_types.h>
|
#include <ccan/short_types/short_types.h>
|
||||||
|
|
||||||
/* Onion message comes in from peer */
|
/* Various messages come in from peer */
|
||||||
|
void handle_obs2_onion_message(struct daemon *daemon,
|
||||||
|
struct peer *peer, const u8 *msg);
|
||||||
void handle_onion_message(struct daemon *daemon,
|
void handle_onion_message(struct daemon *daemon,
|
||||||
struct peer *peer, const u8 *msg);
|
struct peer *peer, const u8 *msg);
|
||||||
|
|
||||||
|
|||||||
414
connectd/test/run-onion_message.c
Normal file
414
connectd/test/run-onion_message.c
Normal file
@@ -0,0 +1,414 @@
|
|||||||
|
#include "config.h"
|
||||||
|
#include "../onion_message.c"
|
||||||
|
#include "common/blindedpath.c"
|
||||||
|
#include "common/blinding.c"
|
||||||
|
#include "common/bigsize.c"
|
||||||
|
#include "common/hmac.c"
|
||||||
|
#include "common/onion.c"
|
||||||
|
#include "common/sphinx.c"
|
||||||
|
#include "wire/fromwire.c"
|
||||||
|
#if EXPERIMENTAL_FEATURES
|
||||||
|
#include "wire/peer_exp_wiregen.c"
|
||||||
|
#include "wire/onion_exp_wiregen.c"
|
||||||
|
#else
|
||||||
|
#include "wire/peer_wiregen.c"
|
||||||
|
#include "wire/onion_wiregen.c"
|
||||||
|
#endif
|
||||||
|
#include "wire/tlvstream.c"
|
||||||
|
|
||||||
|
#include <ccan/str/hex/hex.h>
|
||||||
|
#include <ccan/tal/str/str.h>
|
||||||
|
#include <common/blinding.h>
|
||||||
|
#include <common/channel_type.h>
|
||||||
|
#include <common/ecdh.h>
|
||||||
|
#include <common/json_stream.h>
|
||||||
|
#include <common/onion.h>
|
||||||
|
#include <common/onionreply.h>
|
||||||
|
#include <common/setup.h>
|
||||||
|
#include <secp256k1_ecdh.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* AUTOGENERATED MOCKS START */
|
||||||
|
/* Generated stub for amount_asset_is_main */
|
||||||
|
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
|
||||||
|
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
|
||||||
|
/* Generated stub for amount_asset_to_sat */
|
||||||
|
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
|
||||||
|
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
|
||||||
|
/* Generated stub for amount_msat */
|
||||||
|
struct amount_msat amount_msat(u64 millisatoshis UNNEEDED)
|
||||||
|
{ fprintf(stderr, "amount_msat called!\n"); abort(); }
|
||||||
|
/* Generated stub for amount_msat_eq */
|
||||||
|
bool amount_msat_eq(struct amount_msat a UNNEEDED, struct amount_msat b UNNEEDED)
|
||||||
|
{ fprintf(stderr, "amount_msat_eq called!\n"); abort(); }
|
||||||
|
/* Generated stub for amount_sat */
|
||||||
|
struct amount_sat amount_sat(u64 satoshis UNNEEDED)
|
||||||
|
{ fprintf(stderr, "amount_sat called!\n"); abort(); }
|
||||||
|
/* Generated stub for amount_sat_add */
|
||||||
|
bool amount_sat_add(struct amount_sat *val UNNEEDED,
|
||||||
|
struct amount_sat a UNNEEDED,
|
||||||
|
struct amount_sat b UNNEEDED)
|
||||||
|
{ fprintf(stderr, "amount_sat_add called!\n"); abort(); }
|
||||||
|
/* Generated stub for amount_sat_eq */
|
||||||
|
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
|
||||||
|
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
|
||||||
|
/* Generated stub for amount_sat_greater_eq */
|
||||||
|
bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
|
||||||
|
{ fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); }
|
||||||
|
/* Generated stub for amount_sat_sub */
|
||||||
|
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
|
||||||
|
struct amount_sat a UNNEEDED,
|
||||||
|
struct amount_sat b UNNEEDED)
|
||||||
|
{ fprintf(stderr, "amount_sat_sub called!\n"); abort(); }
|
||||||
|
/* Generated stub for amount_sat_to_asset */
|
||||||
|
struct amount_asset amount_sat_to_asset(struct amount_sat *sat UNNEEDED, const u8 *asset UNNEEDED)
|
||||||
|
{ fprintf(stderr, "amount_sat_to_asset called!\n"); abort(); }
|
||||||
|
/* Generated stub for amount_tx_fee */
|
||||||
|
struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED)
|
||||||
|
{ fprintf(stderr, "amount_tx_fee called!\n"); abort(); }
|
||||||
|
/* Generated stub for daemon_conn_send */
|
||||||
|
void daemon_conn_send(struct daemon_conn *dc UNNEEDED, const u8 *msg UNNEEDED)
|
||||||
|
{ fprintf(stderr, "daemon_conn_send called!\n"); abort(); }
|
||||||
|
/* Generated stub for ecdh */
|
||||||
|
void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED)
|
||||||
|
{ fprintf(stderr, "ecdh called!\n"); abort(); }
|
||||||
|
/* Generated stub for fromwire_amount_msat */
|
||||||
|
struct amount_msat fromwire_amount_msat(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||||
|
{ fprintf(stderr, "fromwire_amount_msat called!\n"); abort(); }
|
||||||
|
/* Generated stub for fromwire_amount_sat */
|
||||||
|
struct amount_sat fromwire_amount_sat(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||||
|
{ fprintf(stderr, "fromwire_amount_sat called!\n"); abort(); }
|
||||||
|
/* Generated stub for fromwire_channel_id */
|
||||||
|
bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
|
||||||
|
struct channel_id *channel_id UNNEEDED)
|
||||||
|
{ fprintf(stderr, "fromwire_channel_id called!\n"); abort(); }
|
||||||
|
/* Generated stub for fromwire_connectd_send_onionmsg */
|
||||||
|
bool fromwire_connectd_send_onionmsg(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, bool *obs2 UNNEEDED, struct node_id *id UNNEEDED, u8 **onion UNNEEDED, struct pubkey *blinding UNNEEDED)
|
||||||
|
{ fprintf(stderr, "fromwire_connectd_send_onionmsg called!\n"); abort(); }
|
||||||
|
/* Generated stub for fromwire_node_id */
|
||||||
|
void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct node_id *id UNNEEDED)
|
||||||
|
{ fprintf(stderr, "fromwire_node_id called!\n"); abort(); }
|
||||||
|
/* Generated stub for fromwire_wireaddr */
|
||||||
|
bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED)
|
||||||
|
{ fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); }
|
||||||
|
/* Generated stub for inject_peer_msg */
|
||||||
|
void inject_peer_msg(struct peer *peer UNNEEDED, const u8 *msg TAKES UNNEEDED)
|
||||||
|
{ fprintf(stderr, "inject_peer_msg called!\n"); abort(); }
|
||||||
|
/* Generated stub for master_badmsg */
|
||||||
|
void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg)
|
||||||
|
{ fprintf(stderr, "master_badmsg called!\n"); abort(); }
|
||||||
|
/* Generated stub for new_onionreply */
|
||||||
|
struct onionreply *new_onionreply(const tal_t *ctx UNNEEDED, const u8 *contents TAKES UNNEEDED)
|
||||||
|
{ fprintf(stderr, "new_onionreply called!\n"); abort(); }
|
||||||
|
/* Generated stub for node_id_from_pubkey */
|
||||||
|
void node_id_from_pubkey(struct node_id *id UNNEEDED, const struct pubkey *key UNNEEDED)
|
||||||
|
{ fprintf(stderr, "node_id_from_pubkey called!\n"); abort(); }
|
||||||
|
/* Generated stub for pubkey_from_node_id */
|
||||||
|
bool pubkey_from_node_id(struct pubkey *key UNNEEDED, const struct node_id *id UNNEEDED)
|
||||||
|
{ fprintf(stderr, "pubkey_from_node_id called!\n"); abort(); }
|
||||||
|
/* Generated stub for status_fmt */
|
||||||
|
void status_fmt(enum log_level level UNNEEDED,
|
||||||
|
const struct node_id *peer UNNEEDED,
|
||||||
|
const char *fmt UNNEEDED, ...)
|
||||||
|
|
||||||
|
{ fprintf(stderr, "status_fmt called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire */
|
||||||
|
void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire_amount_msat */
|
||||||
|
void towire_amount_msat(u8 **pptr UNNEEDED, const struct amount_msat msat UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire_amount_msat called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire_amount_sat */
|
||||||
|
void towire_amount_sat(u8 **pptr UNNEEDED, const struct amount_sat sat UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire_amount_sat called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire_bool */
|
||||||
|
void towire_bool(u8 **pptr UNNEEDED, bool v UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire_bool called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire_channel_id */
|
||||||
|
void towire_channel_id(u8 **pptr UNNEEDED, const struct channel_id *channel_id UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire_channel_id called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire_connectd_got_onionmsg_to_us */
|
||||||
|
u8 *towire_connectd_got_onionmsg_to_us(const tal_t *ctx UNNEEDED, bool obs2 UNNEEDED, const struct pubkey *node_alias UNNEEDED, const struct secret *self_id UNNEEDED, const struct pubkey *reply_blinding UNNEEDED, const struct pubkey *reply_first_node UNNEEDED, const struct onionmsg_path **reply_path UNNEEDED, const u8 *rawmsg UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire_connectd_got_onionmsg_to_us called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire_node_id */
|
||||||
|
void towire_node_id(u8 **pptr UNNEEDED, const struct node_id *id UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire_node_id called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire_pad */
|
||||||
|
void towire_pad(u8 **pptr UNNEEDED, size_t num UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire_pad called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire_secp256k1_ecdsa_signature */
|
||||||
|
void towire_secp256k1_ecdsa_signature(u8 **pptr UNNEEDED,
|
||||||
|
const secp256k1_ecdsa_signature *signature UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire_secp256k1_ecdsa_signature called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire_sha256 */
|
||||||
|
void towire_sha256(u8 **pptr UNNEEDED, const struct sha256 *sha256 UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire_sha256 called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire_tu32 */
|
||||||
|
void towire_tu32(u8 **pptr UNNEEDED, u32 v UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire_tu32 called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire_tu64 */
|
||||||
|
void towire_tu64(u8 **pptr UNNEEDED, u64 v UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire_tu64 called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire_u16 */
|
||||||
|
void towire_u16(u8 **pptr UNNEEDED, u16 v UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire_u16 called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire_u32 */
|
||||||
|
void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire_u32 called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire_u64 */
|
||||||
|
void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire_u64 called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire_u8 */
|
||||||
|
void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire_u8 called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire_u8_array */
|
||||||
|
void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire_u8_array called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire_warningfmt */
|
||||||
|
u8 *towire_warningfmt(const tal_t *ctx UNNEEDED,
|
||||||
|
const struct channel_id *channel UNNEEDED,
|
||||||
|
const char *fmt UNNEEDED, ...)
|
||||||
|
{ fprintf(stderr, "towire_warningfmt called!\n"); abort(); }
|
||||||
|
/* Generated stub for towire_wireaddr */
|
||||||
|
void towire_wireaddr(u8 **pptr UNNEEDED, const struct wireaddr *addr UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire_wireaddr called!\n"); abort(); }
|
||||||
|
/* AUTOGENERATED MOCKS END */
|
||||||
|
|
||||||
|
/* Updated each time, as we pretend to be Alice, Bob, Carol */
|
||||||
|
static const struct privkey *mykey;
|
||||||
|
|
||||||
|
static void test_ecdh(const struct pubkey *point, struct secret *ss)
|
||||||
|
{
|
||||||
|
if (secp256k1_ecdh(secp256k1_ctx, ss->data, &point->pubkey,
|
||||||
|
mykey->secret.data, NULL, NULL) != 1)
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void json_strfield(const char *name, const char *val)
|
||||||
|
{
|
||||||
|
printf("\t\"%s\": \"%s\",\n", name, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void json_onionmsg_payload(const struct tlv_obs2_onionmsg_payload *om)
|
||||||
|
{
|
||||||
|
if (om->reply_path) {
|
||||||
|
printf("\t\"reply_path\": {\n");
|
||||||
|
json_strfield("first_node_id",
|
||||||
|
type_to_string(tmpctx, struct pubkey,
|
||||||
|
&om->reply_path->first_node_id));
|
||||||
|
json_strfield("blinding",
|
||||||
|
type_to_string(tmpctx, struct pubkey,
|
||||||
|
&om->reply_path->blinding));
|
||||||
|
printf("\t\"path\": [\n");
|
||||||
|
for (size_t i = 0; i < tal_count(om->reply_path->path); i++) {
|
||||||
|
json_strfield("node_id",
|
||||||
|
type_to_string(tmpctx, struct pubkey,
|
||||||
|
&om->reply_path->path[i]->node_id));
|
||||||
|
json_strfield("encrypted_recipient_data",
|
||||||
|
tal_hex(tmpctx,
|
||||||
|
om->reply_path->path[i]->encrypted_recipient_data));
|
||||||
|
}
|
||||||
|
printf("]}\n");
|
||||||
|
}
|
||||||
|
if (om->invoice)
|
||||||
|
json_strfield("invoice", tal_hex(tmpctx, om->invoice));
|
||||||
|
if (om->invoice_request)
|
||||||
|
json_strfield("invoice_request",
|
||||||
|
tal_hex(tmpctx, om->invoice_request));
|
||||||
|
if (om->invoice_error)
|
||||||
|
json_strfield("invoice_error",
|
||||||
|
tal_hex(tmpctx, om->invoice_error));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return next onion (and updates blinding), or NULL */
|
||||||
|
static u8 *json_test(const char *testname,
|
||||||
|
const u8 *data,
|
||||||
|
const struct privkey *me,
|
||||||
|
const struct privkey *blinding_priv,
|
||||||
|
struct pubkey *blinding)
|
||||||
|
{
|
||||||
|
struct pubkey my_id, next_node;
|
||||||
|
struct secret ss, onion_ss;
|
||||||
|
struct pubkey ephemeral;
|
||||||
|
struct route_step *rs;
|
||||||
|
const u8 *cursor;
|
||||||
|
size_t max, maxlen;
|
||||||
|
struct onionpacket *op;
|
||||||
|
struct tlv_obs2_onionmsg_payload *om;
|
||||||
|
|
||||||
|
op = parse_onionpacket(tmpctx, data, tal_bytelen(data), NULL);
|
||||||
|
assert(op);
|
||||||
|
|
||||||
|
pubkey_from_privkey(me, &my_id);
|
||||||
|
printf("{");
|
||||||
|
json_strfield("test name", testname);
|
||||||
|
json_strfield("reader_privkey",
|
||||||
|
type_to_string(tmpctx, struct privkey, me));
|
||||||
|
json_strfield("reader_id",
|
||||||
|
type_to_string(tmpctx, struct pubkey, &my_id));
|
||||||
|
|
||||||
|
if (blinding_priv)
|
||||||
|
json_strfield("blinding_privkey",
|
||||||
|
type_to_string(tmpctx, struct privkey,
|
||||||
|
blinding_priv));
|
||||||
|
json_strfield("blinding",
|
||||||
|
type_to_string(tmpctx, struct pubkey, blinding));
|
||||||
|
printf("\"onionmsg\": {\n");
|
||||||
|
json_strfield("raw", tal_hex(tmpctx, data));
|
||||||
|
json_strfield("version", tal_fmt(tmpctx, "%i", op->version));
|
||||||
|
json_strfield("public_key",
|
||||||
|
type_to_string(tmpctx, struct pubkey, &op->ephemeralkey));
|
||||||
|
json_strfield("hop_payloads",
|
||||||
|
tal_hex(tmpctx, op->routinginfo));
|
||||||
|
json_strfield("hmac",
|
||||||
|
tal_hexstr(tmpctx, &op->hmac, sizeof(op->hmac)));
|
||||||
|
printf("},\n");
|
||||||
|
|
||||||
|
ephemeral = op->ephemeralkey;
|
||||||
|
|
||||||
|
/* Set this for test_ecdh */
|
||||||
|
mykey = me;
|
||||||
|
assert(unblind_onion(blinding, test_ecdh, &ephemeral, &ss));
|
||||||
|
json_strfield("ECDH shared secret",
|
||||||
|
type_to_string(tmpctx, struct secret, &ss));
|
||||||
|
/* Reproduce internal calc from unblind_onion */
|
||||||
|
{
|
||||||
|
struct secret hmac;
|
||||||
|
subkey_from_hmac("blinded_node_id", &ss, &hmac);
|
||||||
|
json_strfield("HMAC256(\\\"blinded_node_id\\\", ss(i)) * k(i)",
|
||||||
|
type_to_string(tmpctx, struct secret, &hmac));
|
||||||
|
}
|
||||||
|
json_strfield("Tweaked onion pubkey",
|
||||||
|
type_to_string(tmpctx, struct pubkey, &ephemeral));
|
||||||
|
|
||||||
|
/* Now get onion shared secret and parse it. */
|
||||||
|
test_ecdh(&ephemeral, &onion_ss);
|
||||||
|
json_strfield("onion shared secret",
|
||||||
|
type_to_string(tmpctx, struct secret, &onion_ss));
|
||||||
|
rs = process_onionpacket(tmpctx, op, &onion_ss, NULL, 0, false);
|
||||||
|
assert(rs);
|
||||||
|
|
||||||
|
printf("\"onion contents\": {\n");
|
||||||
|
json_strfield("raw", tal_hex(tmpctx, rs->raw_payload));
|
||||||
|
|
||||||
|
cursor = rs->raw_payload;
|
||||||
|
max = tal_bytelen(rs->raw_payload);
|
||||||
|
maxlen = fromwire_bigsize(&cursor, &max);
|
||||||
|
json_strfield("length", tal_fmt(tmpctx, "%zu", maxlen));
|
||||||
|
json_strfield("rawtlv", tal_hexstr(tmpctx, cursor, maxlen));
|
||||||
|
json_strfield("hmac", tal_hexstr(tmpctx, rs->next->hmac.bytes,
|
||||||
|
sizeof(rs->next->hmac.bytes)));
|
||||||
|
om = fromwire_tlv_obs2_onionmsg_payload(tmpctx, &cursor, &maxlen);
|
||||||
|
assert(om);
|
||||||
|
|
||||||
|
json_onionmsg_payload(om);
|
||||||
|
|
||||||
|
/* We expect one of these. */
|
||||||
|
assert(om->enctlv);
|
||||||
|
|
||||||
|
printf("\t\"encrypted_data_tlv\": {\n");
|
||||||
|
json_strfield("raw", tal_hex(tmpctx, om->enctlv));
|
||||||
|
|
||||||
|
if (rs->nextcase == ONION_END) {
|
||||||
|
struct secret *self_id;
|
||||||
|
struct pubkey alias;
|
||||||
|
assert(decrypt_obs2_final_enctlv(tmpctx,
|
||||||
|
blinding, &ss,
|
||||||
|
om->enctlv,
|
||||||
|
&my_id, &alias, &self_id));
|
||||||
|
if (self_id) {
|
||||||
|
json_strfield("self_id",
|
||||||
|
type_to_string(tmpctx, struct secret,
|
||||||
|
self_id));
|
||||||
|
}
|
||||||
|
printf("}\n");
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
assert(decrypt_obs2_enctlv(blinding, &ss, om->enctlv, &next_node,
|
||||||
|
blinding));
|
||||||
|
json_strfield("next_node",
|
||||||
|
type_to_string(tmpctx, struct pubkey, &next_node));
|
||||||
|
json_strfield("next_blinding",
|
||||||
|
type_to_string(tmpctx, struct pubkey,
|
||||||
|
blinding));
|
||||||
|
printf("}");
|
||||||
|
printf("},\n");
|
||||||
|
return serialize_onionpacket(tmpctx, rs->next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct onionpacket *op;
|
||||||
|
u8 *data;
|
||||||
|
struct privkey alice, bob, carol, dave, blinding_priv;
|
||||||
|
struct pubkey alice_id, bob_id, carol_id, dave_id;
|
||||||
|
struct pubkey blinding;
|
||||||
|
|
||||||
|
common_setup(argv[0]);
|
||||||
|
|
||||||
|
memset(&alice, 'A', sizeof(alice));
|
||||||
|
memset(&bob, 'B', sizeof(bob));
|
||||||
|
memset(&carol, 'C', sizeof(carol));
|
||||||
|
memset(&dave, 'D', sizeof(dave));
|
||||||
|
pubkey_from_privkey(&alice, &alice_id);
|
||||||
|
pubkey_from_privkey(&bob, &bob_id);
|
||||||
|
pubkey_from_privkey(&carol, &carol_id);
|
||||||
|
pubkey_from_privkey(&dave, &dave_id);
|
||||||
|
|
||||||
|
/* ThomasH sends via email:
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* "version":0,
|
||||||
|
* "public_key":
|
||||||
|
* "0256b328b30c8bf5839e24058747879408bdb36241dc9c2e7c619faa12b2920967",
|
||||||
|
* "hop_payloads":
|
||||||
|
* "37df67dcefdb678725cb8074d3224dfe235ba3f22f71ac8a2c9d1398b1175295b1dd3f14c02d698021e8a8856637306c6f195e01494eb8dc636b4462367533a84786b8592e580086cdf0f1c58b77eb68703a2fb82ecc2e91307a25b6d5e4045174551b1c867264d3905e4f05b2e5bcfed7e7276660bf7e956bce5afa395e7e4c15883b856bc93dd9d6a968838ef51314d38dd41e5ab84b8846dca3c61d87e55780e7a7da336a965a4652263413cdef41daa68f7bb7cd4d566c19a1c4eece369c47e604575f38e7a246a985c3441b60ae33c564395bb7a4bbe28325ccdb07503285dacf90b5e09f4e455fb42459741f9d497000298b99f1e70adc28f59a1be85a96952f27b6a6c5d6a08822b4f5cae05daa6c2ce2f8ca5fdd4e8f0df46b94791b3159fe8eace11bcf8d58be425b49ce2b47c007affefd5cea785c1996ad805f8c8c5ca79f15ab26e2bd4080b1d74328e7ce5bd2a579c71a6bd25f33f2ce475a2cfbe67ed1f4eb8fbd86920f41d573488abe059166aabbc3be187c435423ead6a5473994e0246efe76e419893aa2d7566b2645f3496d97585de9c92b8c5a5226398cc459ce84abc02fe2b45b5ecaf21961730d4a34bbe6fdfe720e71e3d81a494c01080d8039360d534c6ee5a3c47a1874e526969add9126b30d9192f85ba45bcfd7029cc7560f0e25e14b5deaa805360c4967705e85325ac055922863470f5397e8404022488caebf9204acd6cb02a11088aebf7e497b4ff1172f0a9c6bf980914cc4eb42fc78b457add549abf1134f84922b217502938b42d10b35079f44c5168d4c3e9fe7ca8094ef72ed73ef84f1d3530b6b3545f9f4f013e7e8cbcf2619f57754a7380ce6a9532ee14c55990faa43df6c09530a314b5f4ce597f5ec9b776e8597ce258ac47dac43bd3ac9e52788ff3a66b7dc07cd1bc3e6d197339d85fa8d3d6c3054dd1a5e416c714b544de6eb55209e40e3cac412a51748370160d2d73b6d97abd62f7bae70df27cd199c511fa693019c5717d471e934906b98cd974fda4dd1cb5e2d721044a0be2bdf24d0971e09f2f39488fe389fc5230699b4df7cec7447e5be4ea49bd7c3fe1a5ec7358510dc1dd9c1a8da68c0863188d80549e49f7c00f57d2009b2427b2aed1569603fc247734039469f9fdf3ddd3a22fa95c5d8066a468327a02b474c9915419af82c8edc67686984767fe7885207c6820f6c2e57cb8fd0bcb9981ebc8065c74e970a5d593c3b73ee25a0877ca096a9f7edfee6d43bd817c7d415fea9abb6f206c61aa36942df9318762a76b9da26d0d41a0ae9eee042a175f82dc134bf6f2d46a218db358d6852940e6e30df4a58ac6cb409e7ce99afe1e3f42768bd617af4d0a235d0ba0dd5075f9cc091784395d30e7e42d4e006db21bea9b45d1f122b75c051e84e2281573ef54ebad053218fff0cc28ea89a06adc218d4134f407654990592e75462f5ee4a463c1e46425222d48761162da8049613cafd7ecc52ff8024e9d58512b958e3a3d12dede84e1441247700bca0f992875349448b430683c756438fd4e91f3d44f3cf624ed21f3c63cf92615ecc201d0cd3159b1b3fccd8f29d2daba9ac5ba87b1dd2f83323a2b2d3176b803ce9c7bdc4bae615925eb22a213df1eeb2f8ff95586536caf042d565984aacf1425a120a5d8d7a9cbb70bf4852e116b89ff5b198d672220af2be4246372e7c3836cf50d732212a3e3346ff92873ace57fa687b2b1aab3e8dc6cb9f93f865d998cff0a1680d9012a9597c90a070e525f66226cc287814f4ac4157b15a0b25aa110946cd69fd404fafd5656669bfd1d9e509eabc004c5a",
|
||||||
|
* "hmac": "564bb85911bea8f90d306f4acdafa1c0887619ac72606b11e6b2765734d810ac"
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
op = tal(tmpctx, struct onionpacket);
|
||||||
|
op->version = 0;
|
||||||
|
assert(pubkey_from_hexstr("0256b328b30c8bf5839e24058747879408bdb36241dc9c2e7c619faa12b2920967", strlen("0256b328b30c8bf5839e24058747879408bdb36241dc9c2e7c619faa12b2920967"), &op->ephemeralkey));
|
||||||
|
assert(hex_decode("564bb85911bea8f90d306f4acdafa1c0887619ac72606b11e6b2765734d810ac",
|
||||||
|
strlen("564bb85911bea8f90d306f4acdafa1c0887619ac72606b11e6b2765734d810ac"),
|
||||||
|
&op->hmac, sizeof(op->hmac)));
|
||||||
|
op->routinginfo = tal_hexdata(op, "37df67dcefdb678725cb8074d3224dfe235ba3f22f71ac8a2c9d1398b1175295b1dd3f14c02d698021e8a8856637306c6f195e01494eb8dc636b4462367533a84786b8592e580086cdf0f1c58b77eb68703a2fb82ecc2e91307a25b6d5e4045174551b1c867264d3905e4f05b2e5bcfed7e7276660bf7e956bce5afa395e7e4c15883b856bc93dd9d6a968838ef51314d38dd41e5ab84b8846dca3c61d87e55780e7a7da336a965a4652263413cdef41daa68f7bb7cd4d566c19a1c4eece369c47e604575f38e7a246a985c3441b60ae33c564395bb7a4bbe28325ccdb07503285dacf90b5e09f4e455fb42459741f9d497000298b99f1e70adc28f59a1be85a96952f27b6a6c5d6a08822b4f5cae05daa6c2ce2f8ca5fdd4e8f0df46b94791b3159fe8eace11bcf8d58be425b49ce2b47c007affefd5cea785c1996ad805f8c8c5ca79f15ab26e2bd4080b1d74328e7ce5bd2a579c71a6bd25f33f2ce475a2cfbe67ed1f4eb8fbd86920f41d573488abe059166aabbc3be187c435423ead6a5473994e0246efe76e419893aa2d7566b2645f3496d97585de9c92b8c5a5226398cc459ce84abc02fe2b45b5ecaf21961730d4a34bbe6fdfe720e71e3d81a494c01080d8039360d534c6ee5a3c47a1874e526969add9126b30d9192f85ba45bcfd7029cc7560f0e25e14b5deaa805360c4967705e85325ac055922863470f5397e8404022488caebf9204acd6cb02a11088aebf7e497b4ff1172f0a9c6bf980914cc4eb42fc78b457add549abf1134f84922b217502938b42d10b35079f44c5168d4c3e9fe7ca8094ef72ed73ef84f1d3530b6b3545f9f4f013e7e8cbcf2619f57754a7380ce6a9532ee14c55990faa43df6c09530a314b5f4ce597f5ec9b776e8597ce258ac47dac43bd3ac9e52788ff3a66b7dc07cd1bc3e6d197339d85fa8d3d6c3054dd1a5e416c714b544de6eb55209e40e3cac412a51748370160d2d73b6d97abd62f7bae70df27cd199c511fa693019c5717d471e934906b98cd974fda4dd1cb5e2d721044a0be2bdf24d0971e09f2f39488fe389fc5230699b4df7cec7447e5be4ea49bd7c3fe1a5ec7358510dc1dd9c1a8da68c0863188d80549e49f7c00f57d2009b2427b2aed1569603fc247734039469f9fdf3ddd3a22fa95c5d8066a468327a02b474c9915419af82c8edc67686984767fe7885207c6820f6c2e57cb8fd0bcb9981ebc8065c74e970a5d593c3b73ee25a0877ca096a9f7edfee6d43bd817c7d415fea9abb6f206c61aa36942df9318762a76b9da26d0d41a0ae9eee042a175f82dc134bf6f2d46a218db358d6852940e6e30df4a58ac6cb409e7ce99afe1e3f42768bd617af4d0a235d0ba0dd5075f9cc091784395d30e7e42d4e006db21bea9b45d1f122b75c051e84e2281573ef54ebad053218fff0cc28ea89a06adc218d4134f407654990592e75462f5ee4a463c1e46425222d48761162da8049613cafd7ecc52ff8024e9d58512b958e3a3d12dede84e1441247700bca0f992875349448b430683c756438fd4e91f3d44f3cf624ed21f3c63cf92615ecc201d0cd3159b1b3fccd8f29d2daba9ac5ba87b1dd2f83323a2b2d3176b803ce9c7bdc4bae615925eb22a213df1eeb2f8ff95586536caf042d565984aacf1425a120a5d8d7a9cbb70bf4852e116b89ff5b198d672220af2be4246372e7c3836cf50d732212a3e3346ff92873ace57fa687b2b1aab3e8dc6cb9f93f865d998cff0a1680d9012a9597c90a070e525f66226cc287814f4ac4157b15a0b25aa110946cd69fd404fafd5656669bfd1d9e509eabc004c5a",
|
||||||
|
strlen("37df67dcefdb678725cb8074d3224dfe235ba3f22f71ac8a2c9d1398b1175295b1dd3f14c02d698021e8a8856637306c6f195e01494eb8dc636b4462367533a84786b8592e580086cdf0f1c58b77eb68703a2fb82ecc2e91307a25b6d5e4045174551b1c867264d3905e4f05b2e5bcfed7e7276660bf7e956bce5afa395e7e4c15883b856bc93dd9d6a968838ef51314d38dd41e5ab84b8846dca3c61d87e55780e7a7da336a965a4652263413cdef41daa68f7bb7cd4d566c19a1c4eece369c47e604575f38e7a246a985c3441b60ae33c564395bb7a4bbe28325ccdb07503285dacf90b5e09f4e455fb42459741f9d497000298b99f1e70adc28f59a1be85a96952f27b6a6c5d6a08822b4f5cae05daa6c2ce2f8ca5fdd4e8f0df46b94791b3159fe8eace11bcf8d58be425b49ce2b47c007affefd5cea785c1996ad805f8c8c5ca79f15ab26e2bd4080b1d74328e7ce5bd2a579c71a6bd25f33f2ce475a2cfbe67ed1f4eb8fbd86920f41d573488abe059166aabbc3be187c435423ead6a5473994e0246efe76e419893aa2d7566b2645f3496d97585de9c92b8c5a5226398cc459ce84abc02fe2b45b5ecaf21961730d4a34bbe6fdfe720e71e3d81a494c01080d8039360d534c6ee5a3c47a1874e526969add9126b30d9192f85ba45bcfd7029cc7560f0e25e14b5deaa805360c4967705e85325ac055922863470f5397e8404022488caebf9204acd6cb02a11088aebf7e497b4ff1172f0a9c6bf980914cc4eb42fc78b457add549abf1134f84922b217502938b42d10b35079f44c5168d4c3e9fe7ca8094ef72ed73ef84f1d3530b6b3545f9f4f013e7e8cbcf2619f57754a7380ce6a9532ee14c55990faa43df6c09530a314b5f4ce597f5ec9b776e8597ce258ac47dac43bd3ac9e52788ff3a66b7dc07cd1bc3e6d197339d85fa8d3d6c3054dd1a5e416c714b544de6eb55209e40e3cac412a51748370160d2d73b6d97abd62f7bae70df27cd199c511fa693019c5717d471e934906b98cd974fda4dd1cb5e2d721044a0be2bdf24d0971e09f2f39488fe389fc5230699b4df7cec7447e5be4ea49bd7c3fe1a5ec7358510dc1dd9c1a8da68c0863188d80549e49f7c00f57d2009b2427b2aed1569603fc247734039469f9fdf3ddd3a22fa95c5d8066a468327a02b474c9915419af82c8edc67686984767fe7885207c6820f6c2e57cb8fd0bcb9981ebc8065c74e970a5d593c3b73ee25a0877ca096a9f7edfee6d43bd817c7d415fea9abb6f206c61aa36942df9318762a76b9da26d0d41a0ae9eee042a175f82dc134bf6f2d46a218db358d6852940e6e30df4a58ac6cb409e7ce99afe1e3f42768bd617af4d0a235d0ba0dd5075f9cc091784395d30e7e42d4e006db21bea9b45d1f122b75c051e84e2281573ef54ebad053218fff0cc28ea89a06adc218d4134f407654990592e75462f5ee4a463c1e46425222d48761162da8049613cafd7ecc52ff8024e9d58512b958e3a3d12dede84e1441247700bca0f992875349448b430683c756438fd4e91f3d44f3cf624ed21f3c63cf92615ecc201d0cd3159b1b3fccd8f29d2daba9ac5ba87b1dd2f83323a2b2d3176b803ce9c7bdc4bae615925eb22a213df1eeb2f8ff95586536caf042d565984aacf1425a120a5d8d7a9cbb70bf4852e116b89ff5b198d672220af2be4246372e7c3836cf50d732212a3e3346ff92873ace57fa687b2b1aab3e8dc6cb9f93f865d998cff0a1680d9012a9597c90a070e525f66226cc287814f4ac4157b15a0b25aa110946cd69fd404fafd5656669bfd1d9e509eabc004c5a"));
|
||||||
|
|
||||||
|
data = serialize_onionpacket(tmpctx, op);
|
||||||
|
printf("[\n");
|
||||||
|
|
||||||
|
memset(&blinding_priv, 5, sizeof(blinding_priv));
|
||||||
|
pubkey_from_privkey(&blinding_priv, &blinding);
|
||||||
|
|
||||||
|
data = json_test("onion message for Alice",
|
||||||
|
data,
|
||||||
|
&alice,
|
||||||
|
&blinding_priv,
|
||||||
|
&blinding);
|
||||||
|
|
||||||
|
data = json_test("onion message for Bob",
|
||||||
|
data,
|
||||||
|
&bob,
|
||||||
|
NULL,
|
||||||
|
&blinding);
|
||||||
|
|
||||||
|
data = json_test("onion message for Carol",
|
||||||
|
data,
|
||||||
|
&carol,
|
||||||
|
NULL,
|
||||||
|
&blinding);
|
||||||
|
|
||||||
|
data = json_test("onion message for Dave",
|
||||||
|
data,
|
||||||
|
&dave,
|
||||||
|
NULL,
|
||||||
|
&blinding);
|
||||||
|
|
||||||
|
assert(!data);
|
||||||
|
printf("]\n");
|
||||||
|
|
||||||
|
common_shutdown();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -134,6 +134,7 @@ static struct lightningd *new_lightningd(const tal_t *ctx)
|
|||||||
ld->dev_no_version_checks = false;
|
ld->dev_no_version_checks = false;
|
||||||
ld->dev_max_funding_unconfirmed = 2016;
|
ld->dev_max_funding_unconfirmed = 2016;
|
||||||
ld->dev_ignore_modern_onion = false;
|
ld->dev_ignore_modern_onion = false;
|
||||||
|
ld->dev_ignore_obsolete_onion = false;
|
||||||
ld->dev_disable_commit = -1;
|
ld->dev_disable_commit = -1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ struct lightningd {
|
|||||||
u32 dev_max_funding_unconfirmed;
|
u32 dev_max_funding_unconfirmed;
|
||||||
|
|
||||||
/* Special switches to test onion compatibility */
|
/* Special switches to test onion compatibility */
|
||||||
bool dev_ignore_modern_onion;
|
bool dev_ignore_modern_onion, dev_ignore_obsolete_onion;
|
||||||
|
|
||||||
/* Tell channeld to disable commits after this many. */
|
/* Tell channeld to disable commits after this many. */
|
||||||
int dev_disable_commit;
|
int dev_disable_commit;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <ccan/mem/mem.h>
|
#include <ccan/mem/mem.h>
|
||||||
#include <common/blindedpath.h>
|
#include <common/blindedpath.h>
|
||||||
#include <common/configdir.h>
|
|
||||||
#include <common/json_command.h>
|
#include <common/json_command.h>
|
||||||
#include <common/json_helpers.h>
|
#include <common/json_helpers.h>
|
||||||
#include <common/json_tok.h>
|
#include <common/json_tok.h>
|
||||||
@@ -22,7 +21,10 @@ struct onion_message_hook_payload {
|
|||||||
struct onionmsg_path **reply_path;
|
struct onionmsg_path **reply_path;
|
||||||
struct pubkey *reply_first_node;
|
struct pubkey *reply_first_node;
|
||||||
struct pubkey *our_alias;
|
struct pubkey *our_alias;
|
||||||
|
|
||||||
|
/* Exactly one of these is set! */
|
||||||
struct tlv_onionmsg_payload *om;
|
struct tlv_onionmsg_payload *om;
|
||||||
|
struct tlv_obs2_onionmsg_payload *obs2_om;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void json_add_blindedpath(struct json_stream *stream,
|
static void json_add_blindedpath(struct json_stream *stream,
|
||||||
@@ -61,9 +63,33 @@ static void onion_message_serialize(struct onion_message_hook_payload *payload,
|
|||||||
payload->reply_path);
|
payload->reply_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deprecated_apis)
|
/* Common convenience fields */
|
||||||
json_add_bool(stream, "obs2", false);
|
if (payload->obs2_om) {
|
||||||
|
json_add_bool(stream, "obs2", true);
|
||||||
|
if (payload->obs2_om->invoice_request)
|
||||||
|
json_add_hex_talarr(stream, "invoice_request",
|
||||||
|
payload->obs2_om->invoice_request);
|
||||||
|
if (payload->obs2_om->invoice)
|
||||||
|
json_add_hex_talarr(stream, "invoice", payload->obs2_om->invoice);
|
||||||
|
|
||||||
|
if (payload->obs2_om->invoice_error)
|
||||||
|
json_add_hex_talarr(stream, "invoice_error",
|
||||||
|
payload->obs2_om->invoice_error);
|
||||||
|
|
||||||
|
json_array_start(stream, "unknown_fields");
|
||||||
|
for (size_t i = 0; i < tal_count(payload->obs2_om->fields); i++) {
|
||||||
|
if (payload->obs2_om->fields[i].meta)
|
||||||
|
continue;
|
||||||
|
json_object_start(stream, NULL);
|
||||||
|
json_add_u64(stream, "number", payload->obs2_om->fields[i].numtype);
|
||||||
|
json_add_hex(stream, "value",
|
||||||
|
payload->obs2_om->fields[i].value,
|
||||||
|
payload->obs2_om->fields[i].length);
|
||||||
|
json_object_end(stream);
|
||||||
|
}
|
||||||
|
json_array_end(stream);
|
||||||
|
} else {
|
||||||
|
json_add_bool(stream, "obs2", false);
|
||||||
if (payload->om->invoice_request)
|
if (payload->om->invoice_request)
|
||||||
json_add_hex_talarr(stream, "invoice_request",
|
json_add_hex_talarr(stream, "invoice_request",
|
||||||
payload->om->invoice_request);
|
payload->om->invoice_request);
|
||||||
@@ -86,7 +112,7 @@ static void onion_message_serialize(struct onion_message_hook_payload *payload,
|
|||||||
json_object_end(stream);
|
json_object_end(stream);
|
||||||
}
|
}
|
||||||
json_array_end(stream);
|
json_array_end(stream);
|
||||||
|
}
|
||||||
json_object_end(stream);
|
json_object_end(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,6 +143,7 @@ void handle_onionmsg_to_us(struct lightningd *ld, const u8 *msg)
|
|||||||
struct onion_message_hook_payload *payload;
|
struct onion_message_hook_payload *payload;
|
||||||
u8 *submsg;
|
u8 *submsg;
|
||||||
struct secret *self_id;
|
struct secret *self_id;
|
||||||
|
bool obs2;
|
||||||
size_t submsglen;
|
size_t submsglen;
|
||||||
const u8 *subptr;
|
const u8 *subptr;
|
||||||
|
|
||||||
@@ -124,6 +151,7 @@ void handle_onionmsg_to_us(struct lightningd *ld, const u8 *msg)
|
|||||||
payload->our_alias = tal(payload, struct pubkey);
|
payload->our_alias = tal(payload, struct pubkey);
|
||||||
|
|
||||||
if (!fromwire_connectd_got_onionmsg_to_us(payload, msg,
|
if (!fromwire_connectd_got_onionmsg_to_us(payload, msg,
|
||||||
|
&obs2,
|
||||||
payload->our_alias,
|
payload->our_alias,
|
||||||
&self_id,
|
&self_id,
|
||||||
&payload->reply_blinding,
|
&payload->reply_blinding,
|
||||||
@@ -136,7 +164,9 @@ void handle_onionmsg_to_us(struct lightningd *ld, const u8 *msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if DEVELOPER
|
#if DEVELOPER
|
||||||
if (ld->dev_ignore_modern_onion)
|
if (!obs2 && ld->dev_ignore_modern_onion)
|
||||||
|
return;
|
||||||
|
if (obs2 && ld->dev_ignore_obsolete_onion)
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -148,12 +178,23 @@ void handle_onionmsg_to_us(struct lightningd *ld, const u8 *msg)
|
|||||||
|
|
||||||
submsglen = tal_bytelen(submsg);
|
submsglen = tal_bytelen(submsg);
|
||||||
subptr = submsg;
|
subptr = submsg;
|
||||||
|
if (obs2) {
|
||||||
|
payload->om = NULL;
|
||||||
|
payload->obs2_om = fromwire_tlv_obs2_onionmsg_payload(payload, &subptr, &submsglen);
|
||||||
|
if (!payload->obs2_om) {
|
||||||
|
log_broken(ld->log, "bad got_obs2_onionmsg_tous om: %s",
|
||||||
|
tal_hex(tmpctx, msg));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
payload->obs2_om = NULL;
|
||||||
payload->om = fromwire_tlv_onionmsg_payload(payload, &subptr, &submsglen);
|
payload->om = fromwire_tlv_onionmsg_payload(payload, &subptr, &submsglen);
|
||||||
if (!payload->om) {
|
if (!payload->om) {
|
||||||
log_broken(ld->log, "bad got_onionmsg_tous om: %s",
|
log_broken(ld->log, "bad got_onionmsg_tous om: %s",
|
||||||
tal_hex(tmpctx, msg));
|
tal_hex(tmpctx, msg));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
tal_free(submsg);
|
tal_free(submsg);
|
||||||
|
|
||||||
/* Make sure connectd gets this right. */
|
/* Make sure connectd gets this right. */
|
||||||
@@ -209,10 +250,11 @@ static struct command_result *param_onion_hops(struct command *cmd,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command_result *json_sendonionmessage(struct command *cmd,
|
static struct command_result *json_sendonionmessage2(struct command *cmd,
|
||||||
const char *buffer,
|
const char *buffer,
|
||||||
const jsmntok_t *obj UNNEEDED,
|
const jsmntok_t *obj UNNEEDED,
|
||||||
const jsmntok_t *params)
|
const jsmntok_t *params,
|
||||||
|
bool obs2)
|
||||||
{
|
{
|
||||||
struct onion_hop *hops;
|
struct onion_hop *hops;
|
||||||
struct node_id *first_id;
|
struct node_id *first_id;
|
||||||
@@ -258,13 +300,29 @@ static struct command_result *json_sendonionmessage(struct command *cmd,
|
|||||||
"Creating onion failed (tlvs too long?)");
|
"Creating onion failed (tlvs too long?)");
|
||||||
|
|
||||||
subd_send_msg(cmd->ld->connectd,
|
subd_send_msg(cmd->ld->connectd,
|
||||||
take(towire_connectd_send_onionmsg(NULL, first_id,
|
take(towire_connectd_send_onionmsg(NULL, obs2, first_id,
|
||||||
serialize_onionpacket(tmpctx, op),
|
serialize_onionpacket(tmpctx, op),
|
||||||
blinding)));
|
blinding)));
|
||||||
|
|
||||||
return command_success(cmd, json_stream_success(cmd));
|
return command_success(cmd, json_stream_success(cmd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct command_result *json_sendonionmessage(struct command *cmd,
|
||||||
|
const char *buffer,
|
||||||
|
const jsmntok_t *obj,
|
||||||
|
const jsmntok_t *params)
|
||||||
|
{
|
||||||
|
return json_sendonionmessage2(cmd, buffer, obj, params, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct command_result *json_sendobs2onionmessage(struct command *cmd,
|
||||||
|
const char *buffer,
|
||||||
|
const jsmntok_t *obj,
|
||||||
|
const jsmntok_t *params)
|
||||||
|
{
|
||||||
|
return json_sendonionmessage2(cmd, buffer, obj, params, true);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct json_command sendonionmessage_command = {
|
static const struct json_command sendonionmessage_command = {
|
||||||
"sendonionmessage",
|
"sendonionmessage",
|
||||||
"utility",
|
"utility",
|
||||||
@@ -273,6 +331,14 @@ static const struct json_command sendonionmessage_command = {
|
|||||||
};
|
};
|
||||||
AUTODATA(json_command, &sendonionmessage_command);
|
AUTODATA(json_command, &sendonionmessage_command);
|
||||||
|
|
||||||
|
static const struct json_command sendobs2onionmessage_command = {
|
||||||
|
"sendobs2onionmessage",
|
||||||
|
"utility",
|
||||||
|
json_sendobs2onionmessage,
|
||||||
|
"Send obsolete message to {first_id}, using {blinding}, encoded over {hops} (id, tlv)"
|
||||||
|
};
|
||||||
|
AUTODATA(json_command, &sendobs2onionmessage_command);
|
||||||
|
|
||||||
static struct command_result *param_pubkeys(struct command *cmd,
|
static struct command_result *param_pubkeys(struct command *cmd,
|
||||||
const char *name,
|
const char *name,
|
||||||
const char *buffer,
|
const char *buffer,
|
||||||
@@ -364,6 +430,32 @@ static struct command_result *json_blindedpath(struct command *cmd,
|
|||||||
json_add_blindedpath(response, "blindedpath",
|
json_add_blindedpath(response, "blindedpath",
|
||||||
&first_blinding_pubkey, &first_node, path);
|
&first_blinding_pubkey, &first_node, path);
|
||||||
|
|
||||||
|
/* Now create obsolete one! */
|
||||||
|
blinding_iter = first_blinding;
|
||||||
|
for (size_t i = 0; i < nhops - 1; i++) {
|
||||||
|
path[i] = tal(path, struct onionmsg_path);
|
||||||
|
path[i]->encrypted_recipient_data = create_obs2_enctlv(path[i],
|
||||||
|
&blinding_iter,
|
||||||
|
&ids[i],
|
||||||
|
&ids[i+1],
|
||||||
|
/* FIXME: Pad? */
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
&blinding_iter,
|
||||||
|
&path[i]->node_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: Add padding! */
|
||||||
|
path[nhops-1] = tal(path, struct onionmsg_path);
|
||||||
|
path[nhops-1]->encrypted_recipient_data = create_obs2_final_enctlv(path[nhops-1],
|
||||||
|
&blinding_iter,
|
||||||
|
&ids[nhops-1],
|
||||||
|
/* FIXME: Pad? */
|
||||||
|
0,
|
||||||
|
&cmd->ld->onion_reply_secret,
|
||||||
|
&path[nhops-1]->node_id);
|
||||||
|
json_add_blindedpath(response, "obs2blindedpath",
|
||||||
|
&first_blinding_pubkey, &first_node, path);
|
||||||
return command_success(cmd, response);
|
return command_success(cmd, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -733,6 +733,9 @@ static void dev_register_opts(struct lightningd *ld)
|
|||||||
opt_register_noarg("--dev-no-modern-onion", opt_set_bool,
|
opt_register_noarg("--dev-no-modern-onion", opt_set_bool,
|
||||||
&ld->dev_ignore_modern_onion,
|
&ld->dev_ignore_modern_onion,
|
||||||
"Ignore modern onion messages");
|
"Ignore modern onion messages");
|
||||||
|
opt_register_noarg("--dev-no-obsolete-onion", opt_set_bool,
|
||||||
|
&ld->dev_ignore_obsolete_onion,
|
||||||
|
"Ignore obsolete onion messages");
|
||||||
opt_register_arg("--dev-disable-commit-after",
|
opt_register_arg("--dev-disable-commit-after",
|
||||||
opt_set_intval, opt_show_intval,
|
opt_set_intval, opt_show_intval,
|
||||||
&ld->dev_disable_commit,
|
&ld->dev_disable_commit,
|
||||||
|
|||||||
@@ -639,13 +639,96 @@ static struct pubkey *path_to_node(const tal_t *ctx,
|
|||||||
/* Marshal arguments for sending onion messages */
|
/* Marshal arguments for sending onion messages */
|
||||||
struct sending {
|
struct sending {
|
||||||
struct sent *sent;
|
struct sent *sent;
|
||||||
struct tlv_onionmsg_payload *payload;
|
const char *msgfield;
|
||||||
|
const u8 *msgval;
|
||||||
|
struct tlv_obs2_onionmsg_payload_reply_path *obs2_reply_path;
|
||||||
struct command_result *(*done)(struct command *cmd,
|
struct command_result *(*done)(struct command *cmd,
|
||||||
const char *buf UNUSED,
|
const char *buf UNUSED,
|
||||||
const jsmntok_t *result UNUSED,
|
const jsmntok_t *result UNUSED,
|
||||||
struct sent *sent);
|
struct sent *sent);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct command_result *
|
||||||
|
send_obs2_message(struct command *cmd,
|
||||||
|
const char *buf,
|
||||||
|
const jsmntok_t *result,
|
||||||
|
struct sending *sending)
|
||||||
|
{
|
||||||
|
struct sent *sent = sending->sent;
|
||||||
|
struct privkey blinding_iter;
|
||||||
|
struct pubkey fwd_blinding, *node_alias;
|
||||||
|
size_t nhops = tal_count(sent->path);
|
||||||
|
struct tlv_obs2_onionmsg_payload **payloads;
|
||||||
|
struct out_req *req;
|
||||||
|
|
||||||
|
/* Now create enctlvs for *forward* path. */
|
||||||
|
randombytes_buf(&blinding_iter, sizeof(blinding_iter));
|
||||||
|
if (!pubkey_from_privkey(&blinding_iter, &fwd_blinding))
|
||||||
|
return command_fail(cmd, LIGHTNINGD,
|
||||||
|
"Could not convert blinding %s to pubkey!",
|
||||||
|
type_to_string(tmpctx, struct privkey,
|
||||||
|
&blinding_iter));
|
||||||
|
|
||||||
|
/* We overallocate: this node (0) doesn't have payload or alias */
|
||||||
|
payloads = tal_arr(cmd, struct tlv_obs2_onionmsg_payload *, nhops);
|
||||||
|
node_alias = tal_arr(cmd, struct pubkey, nhops);
|
||||||
|
|
||||||
|
for (size_t i = 1; i < nhops - 1; i++) {
|
||||||
|
payloads[i] = tlv_obs2_onionmsg_payload_new(payloads);
|
||||||
|
payloads[i]->enctlv = create_obs2_enctlv(payloads[i],
|
||||||
|
&blinding_iter,
|
||||||
|
&sent->path[i],
|
||||||
|
&sent->path[i+1],
|
||||||
|
/* FIXME: Pad? */
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
&blinding_iter,
|
||||||
|
&node_alias[i]);
|
||||||
|
}
|
||||||
|
/* Final payload contains the actual data. */
|
||||||
|
payloads[nhops-1] = tlv_obs2_onionmsg_payload_new(payloads);
|
||||||
|
|
||||||
|
/* We don't include enctlv in final, but it gives us final alias */
|
||||||
|
if (!create_obs2_final_enctlv(tmpctx, &blinding_iter, &sent->path[nhops-1],
|
||||||
|
/* FIXME: Pad? */ 0,
|
||||||
|
NULL,
|
||||||
|
&node_alias[nhops-1])) {
|
||||||
|
/* Should not happen! */
|
||||||
|
return command_fail(cmd, LIGHTNINGD,
|
||||||
|
"Could create final enctlv");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: This interface is a string for sendobsonionmessage! */
|
||||||
|
if (streq(sending->msgfield, "invoice_request")) {
|
||||||
|
payloads[nhops-1]->invoice_request
|
||||||
|
= cast_const(u8 *, sending->msgval);
|
||||||
|
} else {
|
||||||
|
assert(streq(sending->msgfield, "invoice"));
|
||||||
|
payloads[nhops-1]->invoice
|
||||||
|
= cast_const(u8 *, sending->msgval);
|
||||||
|
}
|
||||||
|
payloads[nhops-1]->reply_path = sending->obs2_reply_path;
|
||||||
|
|
||||||
|
req = jsonrpc_request_start(cmd->plugin, cmd, "sendobs2onionmessage",
|
||||||
|
sending->done,
|
||||||
|
forward_error,
|
||||||
|
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");
|
||||||
|
for (size_t i = 1; i < nhops; i++) {
|
||||||
|
u8 *tlv;
|
||||||
|
json_object_start(req->js, NULL);
|
||||||
|
json_add_pubkey(req->js, "id", &node_alias[i]);
|
||||||
|
tlv = tal_arr(tmpctx, u8, 0);
|
||||||
|
towire_tlv_obs2_onionmsg_payload(&tlv, payloads[i]);
|
||||||
|
json_add_hex_talarr(req->js, "tlv", tlv);
|
||||||
|
json_object_end(req->js);
|
||||||
|
}
|
||||||
|
json_array_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,
|
||||||
@@ -683,7 +766,7 @@ send_modern_message(struct command *cmd,
|
|||||||
&node_alias[i]);
|
&node_alias[i]);
|
||||||
}
|
}
|
||||||
/* Final payload contains the actual data. */
|
/* Final payload contains the actual data. */
|
||||||
payloads[nhops-1] = sending->payload;
|
payloads[nhops-1] = tlv_onionmsg_payload_new(payloads);
|
||||||
|
|
||||||
/* We don't include enctlv in final, but it gives us final alias */
|
/* We don't include enctlv in final, but it gives us final alias */
|
||||||
if (!create_final_enctlv(tmpctx, &blinding_iter, &sent->path[nhops-1],
|
if (!create_final_enctlv(tmpctx, &blinding_iter, &sent->path[nhops-1],
|
||||||
@@ -695,12 +778,22 @@ send_modern_message(struct command *cmd,
|
|||||||
"Could create final enctlv");
|
"Could create final enctlv");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FIXME: This interface is a string for sendobsonionmessage! */
|
||||||
|
if (streq(sending->msgfield, "invoice_request")) {
|
||||||
|
payloads[nhops-1]->invoice_request
|
||||||
|
= cast_const(u8 *, sending->msgval);
|
||||||
|
} else {
|
||||||
|
assert(streq(sending->msgfield, "invoice"));
|
||||||
|
payloads[nhops-1]->invoice
|
||||||
|
= cast_const(u8 *, sending->msgval);
|
||||||
|
}
|
||||||
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",
|
||||||
sending->done,
|
/* Try sending older version next */
|
||||||
|
send_obs2_message,
|
||||||
forward_error,
|
forward_error,
|
||||||
sending->sent);
|
sending);
|
||||||
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");
|
||||||
@@ -734,6 +827,15 @@ static struct command_result *use_reply_path(struct command *cmd,
|
|||||||
json_tok_full_len(result),
|
json_tok_full_len(result),
|
||||||
json_tok_full(buf, result));
|
json_tok_full(buf, result));
|
||||||
|
|
||||||
|
sending->obs2_reply_path = json_to_obs2_reply_path(cmd, buf,
|
||||||
|
json_get_member(buf, result,
|
||||||
|
"obs2blindedpath"));
|
||||||
|
if (!sending->obs2_reply_path)
|
||||||
|
plugin_err(cmd->plugin,
|
||||||
|
"could not parse obs2 reply path %.*s?",
|
||||||
|
json_tok_full_len(result),
|
||||||
|
json_tok_full(buf, result));
|
||||||
|
|
||||||
/* Remember our alias we used so we can recognize reply */
|
/* Remember our alias we used so we can recognize reply */
|
||||||
sending->sent->reply_alias
|
sending->sent->reply_alias
|
||||||
= tal_dup(sending->sent, struct pubkey,
|
= tal_dup(sending->sent, struct pubkey,
|
||||||
@@ -769,7 +871,8 @@ static struct command_result *make_reply_path(struct command *cmd,
|
|||||||
|
|
||||||
static struct command_result *send_message(struct command *cmd,
|
static struct command_result *send_message(struct command *cmd,
|
||||||
struct sent *sent,
|
struct sent *sent,
|
||||||
struct tlv_onionmsg_payload *payload STEALS,
|
const char *msgfield TAKES,
|
||||||
|
const u8 *msgval TAKES,
|
||||||
struct command_result *(*done)
|
struct command_result *(*done)
|
||||||
(struct command *cmd,
|
(struct command *cmd,
|
||||||
const char *buf UNUSED,
|
const char *buf UNUSED,
|
||||||
@@ -778,7 +881,8 @@ static struct command_result *send_message(struct command *cmd,
|
|||||||
{
|
{
|
||||||
struct sending *sending = tal(cmd, struct sending);
|
struct sending *sending = tal(cmd, struct sending);
|
||||||
sending->sent = sent;
|
sending->sent = sent;
|
||||||
sending->payload = tal_steal(sending, payload);
|
sending->msgfield = tal_strdup(sending, msgfield);
|
||||||
|
sending->msgval = tal_dup_talarr(sending, u8, msgval);
|
||||||
sending->done = done;
|
sending->done = done;
|
||||||
|
|
||||||
return make_reply_path(cmd, sending);
|
return make_reply_path(cmd, sending);
|
||||||
@@ -817,12 +921,11 @@ sendinvreq_after_connect(struct command *cmd,
|
|||||||
const jsmntok_t *result UNUSED,
|
const jsmntok_t *result UNUSED,
|
||||||
struct sent *sent)
|
struct sent *sent)
|
||||||
{
|
{
|
||||||
struct tlv_onionmsg_payload *payload = tlv_onionmsg_payload_new(sent);
|
u8 *rawinvreq = tal_arr(tmpctx, u8, 0);
|
||||||
|
towire_tlv_invoice_request(&rawinvreq, sent->invreq);
|
||||||
|
|
||||||
payload->invoice_request = tal_arr(payload, u8, 0);
|
return send_message(cmd, sent, "invoice_request", rawinvreq,
|
||||||
towire_tlv_invoice_request(&payload->invoice_request, sent->invreq);
|
sendonionmsg_done);
|
||||||
|
|
||||||
return send_message(cmd, sent, payload, sendonionmsg_done);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct connect_attempt {
|
struct connect_attempt {
|
||||||
@@ -1367,12 +1470,9 @@ sendinvoice_after_connect(struct command *cmd,
|
|||||||
const jsmntok_t *result UNUSED,
|
const jsmntok_t *result UNUSED,
|
||||||
struct sent *sent)
|
struct sent *sent)
|
||||||
{
|
{
|
||||||
struct tlv_onionmsg_payload *payload = tlv_onionmsg_payload_new(sent);
|
u8 *rawinv = tal_arr(tmpctx, u8, 0);
|
||||||
|
towire_tlv_invoice(&rawinv, sent->inv);
|
||||||
payload->invoice = tal_arr(payload, u8, 0);
|
return send_message(cmd, sent, "invoice", rawinv, prepare_inv_timeout);
|
||||||
towire_tlv_invoice(&payload->invoice, sent->inv);
|
|
||||||
|
|
||||||
return send_message(cmd, sent, payload, prepare_inv_timeout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command_result *createinvoice_done(struct command *cmd,
|
static struct command_result *createinvoice_done(struct command *cmd,
|
||||||
|
|||||||
@@ -41,14 +41,65 @@ static struct command_result *sendonionmessage_error(struct command *cmd,
|
|||||||
return command_hook_success(cmd);
|
return command_hook_success(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FIXME: replyfield string interface is to accomodate obsolete API */
|
||||||
|
static struct command_result *
|
||||||
|
send_obs2_onion_reply(struct command *cmd,
|
||||||
|
struct tlv_obs2_onionmsg_payload_reply_path *reply_path,
|
||||||
|
const char *replyfield,
|
||||||
|
const u8 *replydata)
|
||||||
|
{
|
||||||
|
struct out_req *req;
|
||||||
|
size_t nhops = tal_count(reply_path->path);
|
||||||
|
|
||||||
|
req = jsonrpc_request_start(cmd->plugin, cmd, "sendobs2onionmessage",
|
||||||
|
finished, sendonionmessage_error, NULL);
|
||||||
|
|
||||||
|
json_add_pubkey(req->js, "first_id", &reply_path->first_node_id);
|
||||||
|
json_add_pubkey(req->js, "blinding", &reply_path->blinding);
|
||||||
|
json_array_start(req->js, "hops");
|
||||||
|
for (size_t i = 0; i < nhops; i++) {
|
||||||
|
struct tlv_obs2_onionmsg_payload *omp;
|
||||||
|
u8 *tlv;
|
||||||
|
|
||||||
|
json_object_start(req->js, NULL);
|
||||||
|
json_add_pubkey(req->js, "id", &reply_path->path[i]->node_id);
|
||||||
|
|
||||||
|
omp = tlv_obs2_onionmsg_payload_new(tmpctx);
|
||||||
|
omp->enctlv = reply_path->path[i]->encrypted_recipient_data;
|
||||||
|
|
||||||
|
/* Put payload in last hop. */
|
||||||
|
if (i == nhops - 1) {
|
||||||
|
if (streq(replyfield, "invoice")) {
|
||||||
|
omp->invoice = cast_const(u8 *, replydata);
|
||||||
|
} else {
|
||||||
|
assert(streq(replyfield, "invoice_error"));
|
||||||
|
omp->invoice_error = cast_const(u8 *, replydata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tlv = tal_arr(tmpctx, u8, 0);
|
||||||
|
towire_tlv_obs2_onionmsg_payload(&tlv, omp);
|
||||||
|
json_add_hex_talarr(req->js, "tlv", tlv);
|
||||||
|
json_object_end(req->js);
|
||||||
|
}
|
||||||
|
json_array_end(req->js);
|
||||||
|
return send_outreq(cmd->plugin, req);
|
||||||
|
}
|
||||||
|
|
||||||
struct command_result *
|
struct command_result *
|
||||||
send_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,
|
||||||
struct tlv_onionmsg_payload *payload)
|
struct tlv_obs2_onionmsg_payload_reply_path *obs2_reply_path,
|
||||||
|
const char *replyfield,
|
||||||
|
const u8 *replydata)
|
||||||
{
|
{
|
||||||
struct out_req *req;
|
struct out_req *req;
|
||||||
size_t nhops;
|
size_t nhops;
|
||||||
|
|
||||||
|
/* Exactly one must be set! */
|
||||||
|
assert(!reply_path != !obs2_reply_path);
|
||||||
|
if (obs2_reply_path)
|
||||||
|
return send_obs2_onion_reply(cmd, obs2_reply_path, replyfield, replydata);
|
||||||
|
|
||||||
req = jsonrpc_request_start(cmd->plugin, cmd, "sendonionmessage",
|
req = jsonrpc_request_start(cmd->plugin, cmd, "sendonionmessage",
|
||||||
finished, sendonionmessage_error, NULL);
|
finished, sendonionmessage_error, NULL);
|
||||||
|
|
||||||
@@ -64,14 +115,18 @@ send_onion_reply(struct command *cmd,
|
|||||||
json_object_start(req->js, NULL);
|
json_object_start(req->js, NULL);
|
||||||
json_add_pubkey(req->js, "id", &reply_path->path[i]->node_id);
|
json_add_pubkey(req->js, "id", &reply_path->path[i]->node_id);
|
||||||
|
|
||||||
/* Put payload in last hop. */
|
|
||||||
if (i == nhops - 1)
|
|
||||||
omp = payload;
|
|
||||||
else
|
|
||||||
omp = tlv_onionmsg_payload_new(tmpctx);
|
omp = tlv_onionmsg_payload_new(tmpctx);
|
||||||
|
|
||||||
omp->encrypted_data_tlv = reply_path->path[i]->encrypted_recipient_data;
|
omp->encrypted_data_tlv = reply_path->path[i]->encrypted_recipient_data;
|
||||||
|
|
||||||
|
/* Put payload in last hop. */
|
||||||
|
if (i == nhops - 1) {
|
||||||
|
if (streq(replyfield, "invoice")) {
|
||||||
|
omp->invoice = cast_const(u8 *, replydata);
|
||||||
|
} else {
|
||||||
|
assert(streq(replyfield, "invoice_error"));
|
||||||
|
omp->invoice_error = cast_const(u8 *, replydata);
|
||||||
|
}
|
||||||
|
}
|
||||||
tlv = tal_arr(tmpctx, u8, 0);
|
tlv = tal_arr(tmpctx, u8, 0);
|
||||||
towire_tlv_onionmsg_payload(&tlv, omp);
|
towire_tlv_onionmsg_payload(&tlv, omp);
|
||||||
json_add_hex_talarr(req->js, "tlv", tlv);
|
json_add_hex_talarr(req->js, "tlv", tlv);
|
||||||
@@ -86,6 +141,7 @@ static struct command_result *onion_message_modern_call(struct command *cmd,
|
|||||||
const jsmntok_t *params)
|
const jsmntok_t *params)
|
||||||
{
|
{
|
||||||
const jsmntok_t *om, *replytok, *invreqtok, *invtok;
|
const jsmntok_t *om, *replytok, *invreqtok, *invtok;
|
||||||
|
struct tlv_obs2_onionmsg_payload_reply_path *obs2_reply_path = NULL;
|
||||||
struct tlv_onionmsg_payload_reply_path *reply_path = NULL;
|
struct tlv_onionmsg_payload_reply_path *reply_path = NULL;
|
||||||
|
|
||||||
if (!offers_enabled)
|
if (!offers_enabled)
|
||||||
@@ -94,20 +150,31 @@ static struct command_result *onion_message_modern_call(struct command *cmd,
|
|||||||
om = json_get_member(buf, params, "onion_message");
|
om = json_get_member(buf, params, "onion_message");
|
||||||
replytok = json_get_member(buf, om, "reply_blindedpath");
|
replytok = json_get_member(buf, om, "reply_blindedpath");
|
||||||
if (replytok) {
|
if (replytok) {
|
||||||
|
bool obs2;
|
||||||
|
json_to_bool(buf, json_get_member(buf, om, "obs2"), &obs2);
|
||||||
|
if (obs2) {
|
||||||
|
obs2_reply_path = json_to_obs2_reply_path(cmd, buf, replytok);
|
||||||
|
if (!obs2_reply_path)
|
||||||
|
plugin_err(cmd->plugin, "Invalid obs2 reply path %.*s?",
|
||||||
|
json_tok_full_len(replytok),
|
||||||
|
json_tok_full(buf, replytok));
|
||||||
|
} else {
|
||||||
reply_path = json_to_reply_path(cmd, buf, replytok);
|
reply_path = json_to_reply_path(cmd, buf, replytok);
|
||||||
if (!reply_path)
|
if (!reply_path)
|
||||||
plugin_err(cmd->plugin, "Invalid reply path %.*s?",
|
plugin_err(cmd->plugin, "Invalid reply path %.*s?",
|
||||||
json_tok_full_len(replytok),
|
json_tok_full_len(replytok),
|
||||||
json_tok_full(buf, replytok));
|
json_tok_full(buf, replytok));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
const u8 *invreqbin = json_tok_bin_from_hex(tmpctx, buf, invreqtok);
|
||||||
if (reply_path)
|
if (reply_path || obs2_reply_path)
|
||||||
return handle_invoice_request(cmd,
|
return handle_invoice_request(cmd,
|
||||||
invreqbin,
|
invreqbin,
|
||||||
reply_path);
|
reply_path,
|
||||||
|
obs2_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");
|
||||||
@@ -117,7 +184,7 @@ static struct command_result *onion_message_modern_call(struct command *cmd,
|
|||||||
if (invtok) {
|
if (invtok) {
|
||||||
const u8 *invbin = json_tok_bin_from_hex(tmpctx, buf, invtok);
|
const u8 *invbin = json_tok_bin_from_hex(tmpctx, buf, invtok);
|
||||||
if (invbin)
|
if (invbin)
|
||||||
return handle_invoice(cmd, invbin, reply_path);
|
return handle_invoice(cmd, invbin, reply_path, obs2_reply_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return command_hook_success(cmd);
|
return command_hook_success(cmd);
|
||||||
|
|||||||
@@ -10,5 +10,7 @@ struct command;
|
|||||||
struct command_result *WARN_UNUSED_RESULT
|
struct command_result *WARN_UNUSED_RESULT
|
||||||
send_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,
|
||||||
struct tlv_onionmsg_payload *payload);
|
struct tlv_obs2_onionmsg_payload_reply_path *obs2_reply_path,
|
||||||
|
const char *replyfield,
|
||||||
|
const u8 *replydata);
|
||||||
#endif /* LIGHTNING_PLUGINS_OFFERS_H */
|
#endif /* LIGHTNING_PLUGINS_OFFERS_H */
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ struct inv {
|
|||||||
struct tlv_invoice *inv;
|
struct tlv_invoice *inv;
|
||||||
|
|
||||||
/* May be NULL */
|
/* May be NULL */
|
||||||
|
struct tlv_obs2_onionmsg_payload_reply_path *obs2_reply_path;
|
||||||
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. */
|
||||||
@@ -25,8 +26,8 @@ fail_inv_level(struct command *cmd,
|
|||||||
const char *fmt, va_list ap)
|
const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
char *full_fmt, *msg;
|
char *full_fmt, *msg;
|
||||||
struct tlv_onionmsg_payload *payload;
|
|
||||||
struct tlv_invoice_error *err;
|
struct tlv_invoice_error *err;
|
||||||
|
u8 *errdata;
|
||||||
|
|
||||||
full_fmt = tal_fmt(tmpctx, "Failed invoice");
|
full_fmt = tal_fmt(tmpctx, "Failed invoice");
|
||||||
if (inv->inv) {
|
if (inv->inv) {
|
||||||
@@ -43,7 +44,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->reply_path)
|
if (!inv->reply_path && !inv->obs2_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,10 +56,10 @@ fail_inv_level(struct command *cmd,
|
|||||||
err->error = tal_dup_arr(err, char, msg, strlen(msg), 0);
|
err->error = tal_dup_arr(err, char, msg, strlen(msg), 0);
|
||||||
/* FIXME: Add suggested_value / erroneous_field! */
|
/* FIXME: Add suggested_value / erroneous_field! */
|
||||||
|
|
||||||
payload = tlv_onionmsg_payload_new(tmpctx);
|
errdata = tal_arr(cmd, u8, 0);
|
||||||
payload->invoice_error = tal_arr(payload, u8, 0);
|
towire_tlv_invoice_error(&errdata, err);
|
||||||
towire_tlv_invoice_error(&payload->invoice_error, err);
|
return send_onion_reply(cmd, inv->reply_path, inv->obs2_reply_path,
|
||||||
return send_onion_reply(cmd, inv->reply_path, payload);
|
"invoice_error", errdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command_result *WARN_UNUSED_RESULT
|
static struct command_result *WARN_UNUSED_RESULT
|
||||||
@@ -318,7 +319,8 @@ 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 u8 *invbin,
|
const u8 *invbin,
|
||||||
struct tlv_onionmsg_payload_reply_path *reply_path STEALS)
|
struct tlv_onionmsg_payload_reply_path *reply_path STEALS,
|
||||||
|
struct tlv_obs2_onionmsg_payload_reply_path *obs2_reply_path STEALS)
|
||||||
{
|
{
|
||||||
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);
|
||||||
@@ -327,6 +329,7 @@ struct command_result *handle_invoice(struct command *cmd,
|
|||||||
int bad_feature;
|
int bad_feature;
|
||||||
struct sha256 m, shash;
|
struct sha256 m, shash;
|
||||||
|
|
||||||
|
inv->obs2_reply_path = tal_steal(inv, obs2_reply_path);
|
||||||
inv->reply_path = tal_steal(inv, reply_path);
|
inv->reply_path = tal_steal(inv, reply_path);
|
||||||
|
|
||||||
inv->inv = fromwire_tlv_invoice(cmd, &invbin, &len);
|
inv->inv = fromwire_tlv_invoice(cmd, &invbin, &len);
|
||||||
|
|||||||
@@ -6,5 +6,6 @@
|
|||||||
/* We got an onionmessage with an invoice! 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 u8 *invbin,
|
const u8 *invbin,
|
||||||
struct tlv_onionmsg_payload_reply_path *reply_path STEALS);
|
struct tlv_onionmsg_payload_reply_path *reply_path STEALS,
|
||||||
|
struct tlv_obs2_onionmsg_payload_reply_path *obs2_reply_path STEALS);
|
||||||
#endif /* LIGHTNING_PLUGINS_OFFERS_INV_HOOK_H */
|
#endif /* LIGHTNING_PLUGINS_OFFERS_INV_HOOK_H */
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
struct invreq {
|
struct invreq {
|
||||||
struct tlv_invoice_request *invreq;
|
struct tlv_invoice_request *invreq;
|
||||||
struct tlv_onionmsg_payload_reply_path *reply_path;
|
struct tlv_onionmsg_payload_reply_path *reply_path;
|
||||||
|
struct tlv_obs2_onionmsg_payload_reply_path *obs2_reply_path;
|
||||||
|
|
||||||
/* The offer, once we've looked it up. */
|
/* The offer, once we've looked it up. */
|
||||||
struct tlv_offer *offer;
|
struct tlv_offer *offer;
|
||||||
@@ -35,8 +36,8 @@ fail_invreq_level(struct command *cmd,
|
|||||||
const char *fmt, va_list ap)
|
const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
char *full_fmt, *msg;
|
char *full_fmt, *msg;
|
||||||
struct tlv_onionmsg_payload *payload;
|
|
||||||
struct tlv_invoice_error *err;
|
struct tlv_invoice_error *err;
|
||||||
|
u8 *errdata;
|
||||||
|
|
||||||
full_fmt = tal_fmt(tmpctx, "Failed invoice_request");
|
full_fmt = tal_fmt(tmpctx, "Failed invoice_request");
|
||||||
if (invreq->invreq) {
|
if (invreq->invreq) {
|
||||||
@@ -61,10 +62,10 @@ fail_invreq_level(struct command *cmd,
|
|||||||
err->error = tal_dup_arr(err, char, msg, strlen(msg), 0);
|
err->error = tal_dup_arr(err, char, msg, strlen(msg), 0);
|
||||||
/* FIXME: Add suggested_value / erroneous_field! */
|
/* FIXME: Add suggested_value / erroneous_field! */
|
||||||
|
|
||||||
payload = tlv_onionmsg_payload_new(tmpctx);
|
errdata = tal_arr(cmd, u8, 0);
|
||||||
payload->invoice_error = tal_arr(payload, u8, 0);
|
towire_tlv_invoice_error(&errdata, err);
|
||||||
towire_tlv_invoice_error(&payload->invoice_error, err);
|
return send_onion_reply(cmd, invreq->reply_path, invreq->obs2_reply_path,
|
||||||
return send_onion_reply(cmd, invreq->reply_path, payload);
|
"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)
|
||||||
@@ -171,7 +172,6 @@ static struct command_result *createinvoice_done(struct command *cmd,
|
|||||||
{
|
{
|
||||||
char *hrp;
|
char *hrp;
|
||||||
u8 *rawinv;
|
u8 *rawinv;
|
||||||
struct tlv_onionmsg_payload *payload;
|
|
||||||
const jsmntok_t *t;
|
const jsmntok_t *t;
|
||||||
|
|
||||||
/* We have a signed invoice, use it as a reply. */
|
/* We have a signed invoice, use it as a reply. */
|
||||||
@@ -184,9 +184,8 @@ static struct command_result *createinvoice_done(struct command *cmd,
|
|||||||
json_tok_full(buf, t));
|
json_tok_full(buf, t));
|
||||||
}
|
}
|
||||||
|
|
||||||
payload = tlv_onionmsg_payload_new(tmpctx);
|
return send_onion_reply(cmd, ir->reply_path, ir->obs2_reply_path,
|
||||||
payload->invoice = rawinv;
|
"invoice", rawinv);
|
||||||
return send_onion_reply(cmd, ir->reply_path, payload);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct command_result *createinvoice_error(struct command *cmd,
|
static struct command_result *createinvoice_error(struct command *cmd,
|
||||||
@@ -848,13 +847,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 u8 *invreqbin,
|
const u8 *invreqbin,
|
||||||
struct tlv_onionmsg_payload_reply_path *reply_path)
|
struct tlv_onionmsg_payload_reply_path *reply_path,
|
||||||
|
struct tlv_obs2_onionmsg_payload_reply_path *obs2_reply_path)
|
||||||
{
|
{
|
||||||
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;
|
||||||
|
|
||||||
|
ir->obs2_reply_path = tal_steal(ir, obs2_reply_path);
|
||||||
ir->reply_path = tal_steal(ir, reply_path);
|
ir->reply_path = tal_steal(ir, reply_path);
|
||||||
|
|
||||||
ir->invreq = fromwire_tlv_invoice_request(cmd, &invreqbin, &len);
|
ir->invreq = fromwire_tlv_invoice_request(cmd, &invreqbin, &len);
|
||||||
|
|||||||
@@ -8,5 +8,6 @@ extern u16 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 u8 *invreqbin,
|
const u8 *invreqbin,
|
||||||
struct tlv_onionmsg_payload_reply_path *reply_path STEALS);
|
struct tlv_onionmsg_payload_reply_path *reply_path STEALS,
|
||||||
|
struct tlv_obs2_onionmsg_payload_reply_path *obs2_reply_path STEALS);
|
||||||
#endif /* LIGHTNING_PLUGINS_OFFERS_INVREQ_HOOK_H */
|
#endif /* LIGHTNING_PLUGINS_OFFERS_INVREQ_HOOK_H */
|
||||||
|
|||||||
@@ -4479,6 +4479,27 @@ def test_fetchinvoice_3hop(node_factory, bitcoind):
|
|||||||
|
|
||||||
l1.rpc.call('fetchinvoice', {'offer': offer1['bolt12']})
|
l1.rpc.call('fetchinvoice', {'offer': offer1['bolt12']})
|
||||||
|
|
||||||
|
# Make sure l4 handled both onions before shutting down
|
||||||
|
l1.daemon.wait_for_log(r'plugin-fetchinvoice: Received modern onion .*obs2\\":false')
|
||||||
|
l1.daemon.wait_for_log(r'plugin-fetchinvoice: No match for modern onion.*obs2\\":true')
|
||||||
|
|
||||||
|
# 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.
|
||||||
@@ -4775,8 +4796,10 @@ def test_dev_rawrequest(node_factory):
|
|||||||
assert 'invoice' in ret
|
assert 'invoice' in ret
|
||||||
|
|
||||||
|
|
||||||
def test_sendinvoice(node_factory, bitcoind):
|
def do_test_sendinvoice(node_factory, bitcoind, disable):
|
||||||
l2opts = {'experimental-offers': None}
|
l2opts = {'experimental-offers': None}
|
||||||
|
if disable:
|
||||||
|
l2opts[disable] = None
|
||||||
l1, l2 = node_factory.line_graph(2, wait_for_announce=True,
|
l1, l2 = node_factory.line_graph(2, wait_for_announce=True,
|
||||||
opts=[{'experimental-offers': None},
|
opts=[{'experimental-offers': None},
|
||||||
l2opts])
|
l2opts])
|
||||||
@@ -4858,6 +4881,20 @@ def test_sendinvoice(node_factory, bitcoind):
|
|||||||
assert out['amount_received_msat'] == Millisatoshi(10000000)
|
assert out['amount_received_msat'] == Millisatoshi(10000000)
|
||||||
|
|
||||||
|
|
||||||
|
def test_sendinvoice(node_factory, bitcoind):
|
||||||
|
do_test_sendinvoice(node_factory, bitcoind, None)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.developer("needs to --dev-no-obsolete-onion")
|
||||||
|
def test_sendinvoice_modern(node_factory, bitcoind):
|
||||||
|
do_test_sendinvoice(node_factory, bitcoind, 'dev-no-obsolete-onion')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.developer("needs to --dev-no-modern-onion")
|
||||||
|
def test_sendinvoice_obsolete(node_factory, bitcoind):
|
||||||
|
do_test_sendinvoice(node_factory, bitcoind, 'dev-no-modern-onion')
|
||||||
|
|
||||||
|
|
||||||
def test_self_pay(node_factory):
|
def test_self_pay(node_factory):
|
||||||
"""Repro test for issue 4345: pay ourselves via the pay plugin.
|
"""Repro test for issue 4345: pay ourselves via the pay plugin.
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +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,10 @@
|
@@ -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,obs2_onionmsg_payload,reply_path,2
|
||||||
|
+tlvdata,obs2_onionmsg_payload,reply_path,first_node_id,point,
|
||||||
|
+tlvdata,obs2_onionmsg_payload,reply_path,blinding,point,
|
||||||
|
+tlvdata,obs2_onionmsg_payload,reply_path,path,onionmsg_path,...
|
||||||
|
+tlvtype,obs2_onionmsg_payload,enctlv,10
|
||||||
|
+tlvdata,obs2_onionmsg_payload,enctlv,enctlv,byte,...
|
||||||
|
+tlvtype,obs2_onionmsg_payload,invoice_request,64
|
||||||
|
+tlvdata,obs2_onionmsg_payload,invoice_request,invoice_request,byte,...
|
||||||
|
+tlvtype,obs2_onionmsg_payload,invoice,66
|
||||||
|
+tlvdata,obs2_onionmsg_payload,invoice,invoice,byte,...
|
||||||
|
+tlvtype,obs2_onionmsg_payload,invoice_error,68
|
||||||
|
+tlvdata,obs2_onionmsg_payload,invoice_error,invoice_error,byte,...
|
||||||
|
+tlvtype,obs2_encmsg_tlvs,padding,1
|
||||||
|
+tlvdata,obs2_encmsg_tlvs,padding,pad,byte,...
|
||||||
|
+tlvtype,obs2_encmsg_tlvs,next_node_id,4
|
||||||
|
+tlvdata,obs2_encmsg_tlvs,next_node_id,node_id,point,
|
||||||
|
+tlvtype,obs2_encmsg_tlvs,next_blinding,12
|
||||||
|
+tlvdata,obs2_encmsg_tlvs,next_blinding,blinding,point,
|
||||||
|
+tlvtype,obs2_encmsg_tlvs,self_id,14
|
||||||
|
+tlvdata,obs2_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,9 +1,9 @@
|
|||||||
--- wire/onion_wire.csv 2021-11-16 15:17:39.446494580 +1030
|
--- wire/onion_wire.csv 2021-11-16 15:17:39.446494580 +1030
|
||||||
+++ wire/onion_wire.csv.raw 2021-11-16 15:36:00.046441058 +1030
|
+++ wire/onion_wire.csv.raw 2021-11-16 15:36:00.046441058 +1030
|
||||||
@@ -8,10 +8,36 @@
|
@@ -8,10 +8,36 @@
|
||||||
tlvtype,tlv_payload,payment_data,8
|
tlvdata,obs2_encmsg_tlvs,next_blinding,blinding,point,
|
||||||
tlvdata,tlv_payload,payment_data,payment_secret,byte,32
|
tlvtype,obs2_encmsg_tlvs,self_id,14
|
||||||
tlvdata,tlv_payload,payment_data,total_msat,tu64,
|
tlvdata,obs2_encmsg_tlvs,self_id,data,byte,...
|
||||||
+tlvtype,tlv_payload,encrypted_recipient_data,10
|
+tlvtype,tlv_payload,encrypted_recipient_data,10
|
||||||
+tlvdata,tlv_payload,encrypted_recipient_data,encrypted_data,byte,...
|
+tlvdata,tlv_payload,encrypted_recipient_data,encrypted_data,byte,...
|
||||||
+tlvtype,tlv_payload,blinding_point,12
|
+tlvtype,tlv_payload,blinding_point,12
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
+tlvdata,tlv_payload,encrypted_recipient_data,encrypted_data,byte,...
|
+tlvdata,tlv_payload,encrypted_recipient_data,encrypted_data,byte,...
|
||||||
+tlvtype,tlv_payload,blinding_point,12
|
+tlvtype,tlv_payload,blinding_point,12
|
||||||
+tlvdata,tlv_payload,blinding_point,blinding,point,
|
+tlvdata,tlv_payload,blinding_point,blinding,point,
|
||||||
tlvtype,tlv_payload,encrypted_recipient_data,10
|
tlvtype,obs2_onionmsg_payload,reply_path,2
|
||||||
tlvdata,tlv_payload,encrypted_recipient_data,encrypted_data,byte,...
|
tlvdata,obs2_onionmsg_payload,reply_path,first_node_id,point,
|
||||||
tlvtype,tlv_payload,blinding_point,12
|
tlvdata,obs2_onionmsg_payload,reply_path,blinding,point,
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,26 @@ tlvdata,tlv_payload,short_channel_id,short_channel_id,short_channel_id,
|
|||||||
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,obs2_onionmsg_payload,reply_path,2
|
||||||
|
tlvdata,obs2_onionmsg_payload,reply_path,first_node_id,point,
|
||||||
|
tlvdata,obs2_onionmsg_payload,reply_path,blinding,point,
|
||||||
|
tlvdata,obs2_onionmsg_payload,reply_path,path,onionmsg_path,...
|
||||||
|
tlvtype,obs2_onionmsg_payload,enctlv,10
|
||||||
|
tlvdata,obs2_onionmsg_payload,enctlv,enctlv,byte,...
|
||||||
|
tlvtype,obs2_onionmsg_payload,invoice_request,64
|
||||||
|
tlvdata,obs2_onionmsg_payload,invoice_request,invoice_request,byte,...
|
||||||
|
tlvtype,obs2_onionmsg_payload,invoice,66
|
||||||
|
tlvdata,obs2_onionmsg_payload,invoice,invoice,byte,...
|
||||||
|
tlvtype,obs2_onionmsg_payload,invoice_error,68
|
||||||
|
tlvdata,obs2_onionmsg_payload,invoice_error,invoice_error,byte,...
|
||||||
|
tlvtype,obs2_encmsg_tlvs,padding,1
|
||||||
|
tlvdata,obs2_encmsg_tlvs,padding,pad,byte,...
|
||||||
|
tlvtype,obs2_encmsg_tlvs,next_node_id,4
|
||||||
|
tlvdata,obs2_encmsg_tlvs,next_node_id,node_id,point,
|
||||||
|
tlvtype,obs2_encmsg_tlvs,next_blinding,12
|
||||||
|
tlvdata,obs2_encmsg_tlvs,next_blinding,blinding,point,
|
||||||
|
tlvtype,obs2_encmsg_tlvs,self_id,14
|
||||||
|
tlvdata,obs2_encmsg_tlvs,self_id,data,byte,...
|
||||||
tlvtype,tlv_payload,encrypted_recipient_data,10
|
tlvtype,tlv_payload,encrypted_recipient_data,10
|
||||||
tlvdata,tlv_payload,encrypted_recipient_data,encrypted_data,byte,...
|
tlvdata,tlv_payload,encrypted_recipient_data,encrypted_data,byte,...
|
||||||
tlvtype,tlv_payload,blinding_point,12
|
tlvtype,tlv_payload,blinding_point,12
|
||||||
|
|||||||
|
Reference in New Issue
Block a user