mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-22 06:41:44 +01:00
plugins: support failure_message in invoice and htlc_accepted hooks.
As promised in the Changelog when we converted from failcodes to messages internally. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
c9e73dc4e0
commit
faac4b28ad
5 changed files with 91 additions and 83 deletions
|
@ -636,8 +636,8 @@ This hook is called whenever a valid payment for an unpaid invoice has arrived.
|
|||
|
||||
The hook is sparse on purpose, since the plugin can use the JSON-RPC
|
||||
`listinvoices` command to get additional details about this invoice.
|
||||
It can return a non-zero `failure_code` field as defined for final
|
||||
nodes in [BOLT 4][bolt4-failure-codes], a `result` field with the string
|
||||
It can return a `failure_message` field as defined for final
|
||||
nodes in [BOLT 4][bolt4-failure-messages], a `result` field with the string
|
||||
`reject` to fail it with `incorrect_or_unknown_payment_details`, or a
|
||||
`result` field with the string `continue` to accept the payment.
|
||||
|
||||
|
@ -763,12 +763,12 @@ usual checks such as sufficient fees and CLTV deltas are still enforced.
|
|||
```json
|
||||
{
|
||||
"result": "fail",
|
||||
"failure_code": 4301
|
||||
"failure_message": "2002"
|
||||
}
|
||||
```
|
||||
|
||||
`fail` will tell `lightningd` to fail the HTLC with a given numeric
|
||||
`failure_code` (please refer to the [spec][bolt4-failure-codes] for details).
|
||||
`fail` will tell `lightningd` to fail the HTLC with a given hex-encoded
|
||||
`failure_message` (please refer to the [spec][bolt4-failure-messages] for details: `incorrect_or_unknown_payment_details` is the most common).
|
||||
|
||||
```json
|
||||
{
|
||||
|
@ -899,7 +899,7 @@ compatibility should the semantics be changed in future.
|
|||
[jsonrpc-spec]: https://www.jsonrpc.org/specification
|
||||
[jsonrpc-notification-spec]: https://www.jsonrpc.org/specification#notification
|
||||
[bolt4]: https://github.com/lightningnetwork/lightning-rfc/blob/master/04-onion-routing.md
|
||||
[bolt4-failure-codes]: https://github.com/lightningnetwork/lightning-rfc/blob/master/04-onion-routing.md#failure-messages
|
||||
[bolt4-failure-messages]: https://github.com/lightningnetwork/lightning-rfc/blob/master/04-onion-routing.md#failure-messages
|
||||
[bolt2-open-channel]: https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md#the-open_channel-message
|
||||
[sendcustommsg]: lightning-dev-sendcustommsg.7.html
|
||||
[oddok]: https://github.com/lightningnetwork/lightning-rfc/blob/master/00-introduction.md#its-ok-to-be-odd
|
||||
|
|
|
@ -187,33 +187,38 @@ static const u8 *hook_gives_failmsg(const tal_t *ctx,
|
|||
toks[0].end - toks[0].start, buffer);
|
||||
}
|
||||
|
||||
t = json_get_member(buffer, toks, "failure_message");
|
||||
if (t) {
|
||||
const u8 *failmsg = json_tok_bin_from_hex(ctx, buffer, t);
|
||||
if (!failmsg)
|
||||
fatal("Invalid invoice_payment_hook failure_message: %.*s",
|
||||
toks[0].end - toks[1].start, buffer);
|
||||
return failmsg;
|
||||
}
|
||||
|
||||
if (!deprecated_apis)
|
||||
return NULL;
|
||||
|
||||
t = json_get_member(buffer, toks, "failure_code");
|
||||
#ifdef COMPAT_V080
|
||||
if (!t && deprecated_apis) {
|
||||
if (!t) {
|
||||
static bool warned = false;
|
||||
if (!warned) {
|
||||
warned = true;
|
||||
log_unusual(log,
|
||||
"Plugin did not return object with "
|
||||
"'result' or 'failure_code' fields. "
|
||||
"'result' or 'failure_message' fields. "
|
||||
"This is now deprecated and you should "
|
||||
"return {'result': 'continue' } or "
|
||||
"{'result': 'reject'} or "
|
||||
"{'failure_code': 42} instead.");
|
||||
"{'failure_message'... instead.");
|
||||
}
|
||||
return false;
|
||||
return failmsg_incorrect_or_unknown(ctx, hin);
|
||||
}
|
||||
#endif /* defined(COMPAT_V080) */
|
||||
if (!t)
|
||||
fatal("Invalid invoice_payment_hook response, expecting "
|
||||
"'result' or 'failure_code' field: %.*s",
|
||||
toks[0].end - toks[0].start, buffer);
|
||||
|
||||
if (!json_to_number(buffer, t, &val))
|
||||
fatal("Invalid invoice_payment_hook failure_code: %.*s",
|
||||
toks[0].end - toks[1].start, buffer);
|
||||
|
||||
/* FIXME: Allow hook to return its own failmsg directly? */
|
||||
if (val == WIRE_TEMPORARY_NODE_FAILURE)
|
||||
return towire_temporary_node_failure(ctx);
|
||||
if (val != WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS)
|
||||
|
|
|
@ -747,17 +747,50 @@ enum htlc_accepted_result {
|
|||
htlc_accepted_resolve,
|
||||
};
|
||||
|
||||
/* We only handle the simplest cases here */
|
||||
static u8 *convert_failcode(const tal_t *ctx,
|
||||
struct lightningd *ld,
|
||||
unsigned int failure_code)
|
||||
{
|
||||
switch (failure_code) {
|
||||
case WIRE_INVALID_REALM:
|
||||
return towire_invalid_realm(ctx);
|
||||
case WIRE_TEMPORARY_NODE_FAILURE:
|
||||
return towire_temporary_node_failure(ctx);
|
||||
case WIRE_PERMANENT_NODE_FAILURE:
|
||||
return towire_permanent_node_failure(ctx);
|
||||
case WIRE_REQUIRED_NODE_FEATURE_MISSING:
|
||||
return towire_required_node_feature_missing(ctx);
|
||||
case WIRE_CHANNEL_DISABLED:
|
||||
return towire_channel_disabled(ctx);
|
||||
case WIRE_PERMANENT_CHANNEL_FAILURE:
|
||||
return towire_permanent_channel_failure(ctx);
|
||||
case WIRE_REQUIRED_CHANNEL_FEATURE_MISSING:
|
||||
return towire_required_channel_feature_missing(ctx);
|
||||
case WIRE_UNKNOWN_NEXT_PEER:
|
||||
return towire_unknown_next_peer(ctx);
|
||||
default:
|
||||
log_broken(ld->log,
|
||||
"htlc_accepted_hook plugin returned failure_code %u,"
|
||||
" turning to WIRE_TEMPORARY_NODE_FAILURE",
|
||||
failure_code);
|
||||
return towire_temporary_node_failure(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the JSON-RPC response into a struct understood by the callback.
|
||||
*/
|
||||
static enum htlc_accepted_result htlc_accepted_hook_deserialize(const char *buffer, const jsmntok_t *toks,
|
||||
/* If accepted */
|
||||
struct preimage *payment_preimage,
|
||||
/* If rejected */
|
||||
enum onion_type *failure_code,
|
||||
u8 **channel_update)
|
||||
static enum htlc_accepted_result
|
||||
htlc_accepted_hook_deserialize(const tal_t *ctx,
|
||||
struct lightningd *ld,
|
||||
const char *buffer, const jsmntok_t *toks,
|
||||
/* If accepted */
|
||||
struct preimage *payment_preimage,
|
||||
/* If rejected (tallocated off ctx) */
|
||||
const u8 **failmsg)
|
||||
{
|
||||
const jsmntok_t *resulttok, *failcodetok, *paykeytok, *chanupdtok;
|
||||
const jsmntok_t *resulttok, *paykeytok;
|
||||
enum htlc_accepted_result result;
|
||||
|
||||
if (!toks || !buffer)
|
||||
|
@ -777,23 +810,31 @@ static enum htlc_accepted_result htlc_accepted_hook_deserialize(const char *buff
|
|||
}
|
||||
|
||||
if (json_tok_streq(buffer, resulttok, "fail")) {
|
||||
const jsmntok_t *failmsgtok, *failcodetok;
|
||||
|
||||
result = htlc_accepted_fail;
|
||||
failcodetok = json_get_member(buffer, toks, "failure_code");
|
||||
chanupdtok = json_get_member(buffer, toks, "channel_update");
|
||||
if (failcodetok &&
|
||||
!json_to_number(buffer, failcodetok, failure_code))
|
||||
fatal("Plugin provided a non-numeric failcode "
|
||||
"in response to an htlc_accepted hook");
|
||||
|
||||
if (!failcodetok)
|
||||
*failure_code = WIRE_TEMPORARY_NODE_FAILURE;
|
||||
|
||||
if (chanupdtok)
|
||||
*channel_update =
|
||||
json_tok_bin_from_hex(buffer, buffer, chanupdtok);
|
||||
else
|
||||
*channel_update = NULL;
|
||||
|
||||
failmsgtok = json_get_member(buffer, toks, "failure_message");
|
||||
if (failmsgtok) {
|
||||
*failmsg = json_tok_bin_from_hex(ctx, buffer,
|
||||
failmsgtok);
|
||||
if (!*failmsg)
|
||||
fatal("Bad failure_message for htlc_accepted"
|
||||
" hook: %.*s",
|
||||
failmsgtok->end - failmsgtok->start,
|
||||
buffer + failmsgtok->start);
|
||||
} else if (deprecated_apis
|
||||
&& (failcodetok = json_get_member(buffer, toks,
|
||||
"failure_code"))) {
|
||||
unsigned int failcode;
|
||||
if (!json_to_number(buffer, failcodetok, &failcode))
|
||||
fatal("Bad failure_code for htlc_accepted"
|
||||
" hook: %.*s",
|
||||
failcodetok->end
|
||||
- failcodetok->start,
|
||||
buffer + failcodetok->start);
|
||||
*failmsg = convert_failcode(ctx, ld, failcode);
|
||||
} else
|
||||
*failmsg = towire_temporary_node_failure(ctx);
|
||||
} else if (json_tok_streq(buffer, resulttok, "resolve")) {
|
||||
result = htlc_accepted_resolve;
|
||||
paykeytok = json_get_member(buffer, toks, "payment_key");
|
||||
|
@ -888,10 +929,8 @@ htlc_accepted_hook_callback(struct htlc_accepted_hook_payload *request,
|
|||
struct preimage payment_preimage;
|
||||
u8 *req;
|
||||
enum htlc_accepted_result result;
|
||||
enum onion_type failure_code;
|
||||
const u8 *failmsg;
|
||||
u8 *channel_update;
|
||||
result = htlc_accepted_hook_deserialize(buffer, toks, &payment_preimage, &failure_code, &channel_update);
|
||||
result = htlc_accepted_hook_deserialize(request, ld, buffer, toks, &payment_preimage, &failmsg);
|
||||
|
||||
switch (result) {
|
||||
case htlc_accepted_continue:
|
||||
|
@ -925,40 +964,6 @@ htlc_accepted_hook_callback(struct htlc_accepted_hook_payload *request,
|
|||
case htlc_accepted_fail:
|
||||
log_debug(channel->log,
|
||||
"Failing incoming HTLC as instructed by plugin hook");
|
||||
/* FIXME: Deprecate failure_code in favor of failure_message! */
|
||||
/* We only handle the simplest cases here */
|
||||
switch (failure_code) {
|
||||
case WIRE_INVALID_REALM:
|
||||
failmsg = towire_invalid_realm(NULL);
|
||||
break;
|
||||
case WIRE_TEMPORARY_NODE_FAILURE:
|
||||
failmsg = towire_temporary_node_failure(NULL);
|
||||
break;
|
||||
case WIRE_PERMANENT_NODE_FAILURE:
|
||||
failmsg = towire_permanent_node_failure(NULL);
|
||||
break;
|
||||
case WIRE_REQUIRED_NODE_FEATURE_MISSING:
|
||||
failmsg = towire_required_node_feature_missing(NULL);
|
||||
break;
|
||||
case WIRE_CHANNEL_DISABLED:
|
||||
failmsg = towire_channel_disabled(NULL);
|
||||
break;
|
||||
case WIRE_PERMANENT_CHANNEL_FAILURE:
|
||||
failmsg = towire_permanent_channel_failure(NULL);
|
||||
break;
|
||||
case WIRE_REQUIRED_CHANNEL_FEATURE_MISSING:
|
||||
failmsg = towire_required_channel_feature_missing(NULL);
|
||||
break;
|
||||
case WIRE_UNKNOWN_NEXT_PEER:
|
||||
failmsg = towire_unknown_next_peer(NULL);
|
||||
break;
|
||||
default:
|
||||
log_broken(channel->log,
|
||||
"htlc_accepted_hook plugin returned %u,"
|
||||
" turning to WIRE_TEMPORARY_NODE_FAILURE",
|
||||
failure_code);
|
||||
failmsg = towire_temporary_node_failure(NULL);
|
||||
}
|
||||
local_fail_in_htlc(hin, take(failmsg));
|
||||
break;
|
||||
case htlc_accepted_resolve:
|
||||
|
|
|
@ -9,9 +9,8 @@ plugin = Plugin()
|
|||
def on_htlc_accepted(onion, plugin, **kwargs):
|
||||
plugin.log("Failing htlc on purpose")
|
||||
plugin.log("onion: %r" % (onion))
|
||||
# FIXME: Define this!
|
||||
WIRE_TEMPORARY_NODE_FAILURE = 0x2002
|
||||
return {"result": "fail", "failure_code": WIRE_TEMPORARY_NODE_FAILURE}
|
||||
# WIRE_TEMPORARY_NODE_FAILURE = 0x2002
|
||||
return {"result": "fail", "failure_message": "2002"}
|
||||
|
||||
|
||||
plugin.run()
|
||||
|
|
|
@ -16,9 +16,8 @@ def on_payment(payment, plugin, **kwargs):
|
|||
print("preimage={}".format(payment['preimage']))
|
||||
|
||||
if payment['preimage'].endswith('0'):
|
||||
# FIXME: Define this!
|
||||
WIRE_TEMPORARY_NODE_FAILURE = 0x2002
|
||||
return {'failure_code': WIRE_TEMPORARY_NODE_FAILURE}
|
||||
# WIRE_TEMPORARY_NODE_FAILURE = 0x2002
|
||||
return {'failure_message': "2002"}
|
||||
|
||||
return {'result': 'continue'}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue