Skip to content

Commit

Permalink
keysend: try to find description in TLV.
Browse files Browse the repository at this point in the history
"Who needs specs?"  FFS...

Signed-off-by: Rusty Russell <[email protected]>
Changelog-Added: Protocol: `keysend` will now attach the longest valid text field in the onion to the invoice (so you can have Sphinx.chat users spam you!)
  • Loading branch information
rustyrussell committed Sep 22, 2022
1 parent 41502be commit ce0f544
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 11 deletions.
27 changes: 21 additions & 6 deletions plugins/keysend.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,9 +341,8 @@ static struct command_result *htlc_accepted_call(struct command *cmd,
struct sha256 payment_hash;
size_t max;
struct tlv_tlv_payload *payload;
struct tlv_field *preimage_field = NULL, *unknown_field = NULL;
struct tlv_field *preimage_field = NULL, *unknown_field = NULL, *desc_field = NULL;
bigsize_t s;
struct tlv_field *field;
struct keysend_in *ki;
struct out_req *req;
struct timeabs now = time_now();
Expand Down Expand Up @@ -387,15 +386,21 @@ static struct command_result *htlc_accepted_call(struct command *cmd,
}

/* Try looking for the field that contains the preimage */
for (int i=0; i<tal_count(payload->fields); i++) {
field = &payload->fields[i];
for (size_t i = 0; i < tal_count(payload->fields); i++) {
struct tlv_field *field = &payload->fields[i];
if (field->numtype == PREIMAGE_TLV_TYPE) {
preimage_field = field;
break;
continue;
} else if (field->numtype % 2 == 0 && field->meta == NULL) {
/* This can only happen with FROMWIRE_TLV_ANY_TYPE! */
unknown_field = field;
}

/* Longest (unknown) text field wins. */
if (!field->meta
&& utf8_check(field->value, field->length)
&& (!desc_field || field->length > desc_field->length))
desc_field = field;
}

/* If we don't have a preimage field then this is not a keysend, let
Expand Down Expand Up @@ -464,7 +469,17 @@ static struct command_result *htlc_accepted_call(struct command *cmd,
plugin_log(cmd->plugin, LOG_INFORM, "Inserting a new invoice for keysend with payment_hash %s", type_to_string(tmpctx, struct sha256, &payment_hash));
json_add_string(req->js, "amount_msat", "any");
json_add_string(req->js, "label", ki->label);
json_add_string(req->js, "description", "Spontaneous incoming payment through keysend");
if (desc_field) {
const char *desc = tal_fmt(tmpctx, "keysend: %.*s",
(int)desc_field->length,
(const char *)desc_field->value);
json_add_string(req->js, "description", desc);
/* Don't exceed max possible desc length! */
if (strlen(desc) > 1023)
json_add_bool(req->js, "deschashonly", true);
} else {
json_add_string(req->js, "description", "keysend");
}
json_add_preimage(req->js, "preimage", &ki->payment_preimage);

return send_outreq(cmd->plugin, req);
Expand Down
26 changes: 21 additions & 5 deletions tests/test_pay.py
Original file line number Diff line number Diff line change
Expand Up @@ -3585,17 +3585,33 @@ def test_keysend_extra_tlvs(node_factory):
]
)

# Send an indirect one from l1 to l3
l1.rpc.keysend(l2.info['id'], amt, extratlvs={133773310: 'FEEDC0DE'})
invs = l2.rpc.listinvoices()['invoices']
assert(len(invs) == 1)
inv = only_one(l2.rpc.listinvoices()['invoices'])
assert(l2.daemon.is_in_log(r'plugin-sphinx-receiver.py.*extratlvs.*133773310.*feedc0de'))

inv = invs[0]
assert(inv['amount_received_msat'] >= Millisatoshi(amt))
assert inv['description'] == 'keysend'
l2.rpc.delinvoice(inv['label'], 'paid')

# Now try again with the TLV type in extra_tlvs as string:
l1.rpc.keysend(l2.info['id'], amt, extratlvs={133773310: 'FEEDC0DE'})
l1.rpc.keysend(l2.info['id'], amt, extratlvs={133773310: b'hello there'.hex()})
inv = only_one(l2.rpc.listinvoices()['invoices'])
assert inv['description'] == 'keysend: hello there'
l2.rpc.delinvoice(inv['label'], 'paid')

# We can (just!) fit a giant description in.
l1.rpc.keysend(l2.info['id'], amt, extratlvs={133773310: (b'a' * 1100).hex()})
inv = only_one(l2.rpc.listinvoices()['invoices'])
assert inv['description'] == 'keysend: ' + 'a' * 1100
l2.rpc.delinvoice(inv['label'], 'paid')

# Now try with some special characters
ksinfo = """💕 ₿"'
More info
"""
l1.rpc.keysend(l2.info['id'], amt, extratlvs={133773310: bytes(ksinfo, encoding='utf8').hex()})
inv = only_one(l2.rpc.listinvoices()['invoices'])
assert inv['description'] == 'keysend: ' + ksinfo


def test_keysend_routehint(node_factory):
Expand Down

0 comments on commit ce0f544

Please sign in to comment.