keysend: try to find description in TLV.

"Who needs specs?"  FFS...

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
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!)
This commit is contained in:
Rusty Russell 2022-09-21 13:27:37 +09:30
parent 41502be60a
commit ce0f544073
2 changed files with 42 additions and 11 deletions

View file

@ -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();
@ -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
@ -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);

View file

@ -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):