Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- bolt11: support for parsing feature bits (field `9`).

- Protocol: we now retransmit `funding_locked` upon reconnection while closing if there was no update
- Plugin: new notifications `sendpay_success` and `sendpay_failure`.

### Changed

- JSON API: `txprepare` now uses `outputs` as parameter other than `destination` and `satoshi`
Expand Down
62 changes: 62 additions & 0 deletions doc/PLUGINS.md
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,68 @@ or
only `settled` and `failed` case contain `resolved_time`;
- The `failcode` and `failreason` are defined in [BOLT 4][bolt4-failure-codes].

#### `sendpay_success`

A notification for topic `sendpay_success` is sent every time a sendpay
success(with `complete` status). The json is same as the return value of
command `sendpay`/`waitsendpay` when these cammand succeeds.

```json
{
"sendpay_success": {
"id": 1,
"payment_hash": "5c85bf402b87d4860f4a728e2e58a2418bda92cd7aea0ce494f11670cfbfb206",
"destination": "035d2b1192dfba134e10e540875d366ebc8bc353d5aa766b80c090b39c3a5d885d",
"msatoshi": 100000000,
"amount_msat": "100000000msat",
"msatoshi_sent": 100001001,
"amount_sent_msat": "100001001msat",
"created_at": 1561390572,
"status": "complete",
"payment_preimage": "9540d98095fd7f37687ebb7759e733934234d4f934e34433d4998a37de3733ee"
}
}
```
`sendpay` doesn't wait for the result of sendpay and `waitsendpay`
returns the result of sendpay in specified time or timeout, but
`sendpay_success` will always return the result anytime when sendpay
successes if is was subscribed.

#### `sendpay_failure`

A notification for topic `sendpay_failure` is sent every time a sendpay
success(with `failed` status). The json is same as the return value of
command `sendpay`/`waitsendpay` when this cammand fails.

```json
{
"sendpay_failure": {
"code": 204,
"message": "failed: WIRE_UNKNOWN_NEXT_PEER (reply from remote)",
"data": {
"id": 2,
"payment_hash": "9036e3bdbd2515f1e653cb9f22f8e4c49b73aa2c36e937c926f43e33b8db8851",
"destination": "035d2b1192dfba134e10e540875d366ebc8bc353d5aa766b80c090b39c3a5d885d",
"msatoshi": 100000000,
"amount_msat": "100000000msat",
"msatoshi_sent": 100001001,
"amount_sent_msat": "100001001msat",
"created_at": 1561395134,
"status": "failed",
"erring_index": 1,
"failcode": 16394,
"failcodename": "WIRE_UNKNOWN_NEXT_PEER",
"erring_node": "022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59",
"erring_channel": "103x2x1",
"erring_direction": 0
}
}
}
```
`sendpay` doesn't wait for the result of sendpay and `waitsendpay`
returns the result of sendpay in specified time or timeout, but
`sendpay_failure` will always return the result anytime when sendpay
fails if is was subscribed.

## Hooks

Expand Down
73 changes: 73 additions & 0 deletions lightningd/notification.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,76 @@ void notify_forward_event(struct lightningd *ld,
jsonrpc_notification_end(n);
plugins_notify(ld->plugins, take(n));
}

static void sendpay_success_notification_serialize(struct json_stream *stream,
const struct wallet_payment *payment)
{
json_object_start(stream, "sendpay_success");
json_add_payment_fields(stream, payment);
json_object_end(stream); /* .sendpay_success */
}

REGISTER_NOTIFICATION(sendpay_success,
sendpay_success_notification_serialize);

void notify_sendpay_success(struct lightningd *ld,
const struct wallet_payment *payment)
{
void (*serialize)(struct json_stream *,
const struct wallet_payment *) = sendpay_success_notification_gen.serialize;

struct jsonrpc_notification *n =
jsonrpc_notification_start(NULL, "sendpay_success");
serialize(n->stream, payment);
jsonrpc_notification_end(n);
plugins_notify(ld->plugins, take(n));
}

static void sendpay_failure_notification_serialize(struct json_stream *stream,
const struct wallet_payment *payment,
int pay_errcode,
const u8 *onionreply,
const struct routing_failure *fail,
char *errmsg)
{
json_object_start(stream, "sendpay_failure");

/* In line with the format of json error returned
* by sendpay_fail(). */
json_add_member(stream, "code", false, "%d", pay_errcode);
json_add_string(stream, "message", errmsg);

json_object_start(stream, "data");
json_sendpay_fail_fields(stream,
payment,
pay_errcode,
onionreply,
fail);

json_object_end(stream); /* .data */
json_object_end(stream); /* .sendpay_failure */
}

REGISTER_NOTIFICATION(sendpay_failure,
sendpay_failure_notification_serialize);

void notify_sendpay_failure(struct lightningd *ld,
const struct wallet_payment *payment,
int pay_errcode,
const u8 *onionreply,
const struct routing_failure *fail,
char *errmsg)
{
void (*serialize)(struct json_stream *,
const struct wallet_payment *,
int,
const u8 *,
const struct routing_failure *,
char *) = sendpay_failure_notification_gen.serialize;

struct jsonrpc_notification *n =
jsonrpc_notification_start(NULL, "sendpay_failure");
serialize(n->stream, payment, pay_errcode, onionreply, fail, errmsg);
jsonrpc_notification_end(n);
plugins_notify(ld->plugins, take(n));
}
11 changes: 11 additions & 0 deletions lightningd/notification.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <lightningd/jsonrpc.h>
#include <lightningd/lightningd.h>
#include <lightningd/log.h>
#include <lightningd/pay.h>
#include <lightningd/plugin.h>
#include <wallet/wallet.h>
#include <wire/gen_onion_wire.h>
Expand Down Expand Up @@ -54,4 +55,14 @@ void notify_forward_event(struct lightningd *ld,
enum onion_type failcode,
struct timeabs *resolved_time);

void notify_sendpay_success(struct lightningd *ld,
const struct wallet_payment *payment);

void notify_sendpay_failure(struct lightningd *ld,
const struct wallet_payment *payment,
int pay_errcode,
const u8 *onionreply,
const struct routing_failure *fail,
char *errmsg);

#endif /* LIGHTNING_LIGHTNINGD_NOTIFICATION_H */
88 changes: 60 additions & 28 deletions lightningd/pay.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <lightningd/jsonrpc.h>
#include <lightningd/lightningd.h>
#include <lightningd/log.h>
#include <lightningd/notification.h>
#include <lightningd/options.h>
#include <lightningd/peer_control.h>
#include <lightningd/peer_htlcs.h>
Expand Down Expand Up @@ -73,9 +74,8 @@ add_waitsendpay_waiter(struct lightningd *ld,
}

/* Outputs fields, not a separate object*/
static void
json_add_payment_fields(struct json_stream *response,
const struct wallet_payment *t)
void json_add_payment_fields(struct json_stream *response,
const struct wallet_payment *t)
{
json_add_u64(response, "id", t->id);
json_add_sha256(response, "payment_hash", &t->payment_hash);
Expand Down Expand Up @@ -114,6 +114,7 @@ static struct command_result *sendpay_success(struct command *cmd,

assert(payment->status == PAYMENT_COMPLETE);

notify_sendpay_success(cmd->ld, payment);
response = json_stream_success(cmd);
json_add_payment_fields(response, payment);
return command_success(cmd, response);
Expand Down Expand Up @@ -142,36 +143,62 @@ json_add_routefail_info(struct json_stream *js,
json_add_hex_talarr(js, "raw_message", msg);
}

void json_sendpay_fail_fields(struct json_stream *js,
const struct wallet_payment *payment,
int pay_errcode,
const u8 *onionreply,
const struct routing_failure *fail)
{
/* "immediate_routing_failure" is before payment creation. */
if (payment)
json_add_payment_fields(js, payment);
if (pay_errcode == PAY_UNPARSEABLE_ONION)
json_add_hex_talarr(js, "onionreply", onionreply);
else
json_add_routefail_info(js,
fail->erring_index,
fail->failcode,
&fail->erring_node,
&fail->erring_channel,
fail->channel_dir,
fail->msg);
}

/* onionreply used if pay_errcode == PAY_UNPARSEABLE_ONION */
static struct command_result *
sendpay_fail(struct command *cmd,
const struct wallet_payment *payment,
int pay_errcode,
const u8 *onionreply,
const struct routing_failure *fail,
const char *details)
{
struct json_stream *data;

if (pay_errcode == PAY_UNPARSEABLE_ONION) {
data = json_stream_fail(cmd, PAY_UNPARSEABLE_ONION,
"Malformed error reply");
json_add_hex_talarr(data, "onionreply", onionreply);
json_object_end(data);
return command_failed(cmd, data);
char *errmsg;

if (pay_errcode == PAY_UNPARSEABLE_ONION)
errmsg = "Malformed error reply";
else {
assert(fail);
errmsg = tal_fmt(tmpctx, "failed: %s (%s)",
onion_type_name(fail->failcode),
details);
}

assert(fail);
notify_sendpay_failure(cmd->ld,
payment,
pay_errcode,
onionreply,
fail,
errmsg);

data = json_stream_fail(cmd, pay_errcode,
tal_fmt(tmpctx, "failed: %s (%s)",
onion_type_name(fail->failcode),
details));
json_add_routefail_info(data,
fail->erring_index,
fail->failcode,
&fail->erring_node,
&fail->erring_channel,
fail->channel_dir,
fail->msg);
errmsg);
json_sendpay_fail_fields(data,
payment,
pay_errcode,
onionreply,
fail);
json_object_end(data);
return command_failed(cmd, data);
}
Expand All @@ -190,6 +217,7 @@ json_sendpay_in_progress(struct command *cmd,

static void tell_waiters_failed(struct lightningd *ld,
const struct sha256 *payment_hash,
const struct wallet_payment *payment,
int pay_errcode,
const u8 *onionreply,
const struct routing_failure *fail,
Expand All @@ -203,7 +231,8 @@ static void tell_waiters_failed(struct lightningd *ld,
if (!sha256_eq(payment_hash, &pc->payment_hash))
continue;

sendpay_fail(pc->cmd, pay_errcode, onionreply, fail, details);
sendpay_fail(pc->cmd, payment,
pay_errcode, onionreply, fail, details);
}
}

Expand Down Expand Up @@ -498,11 +527,11 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout,
failmsg,
fail ? fail->channel_dir : 0);

tell_waiters_failed(ld, &hout->payment_hash, pay_errcode,
hout->failuremsg, fail, failmsg);
tell_waiters_failed(ld, &hout->payment_hash, payment,
pay_errcode, hout->failuremsg, fail, failmsg);
}

/* Wait for a payment. If cmd is deleted, then json_waitsendpay_on_resolve
/* Wait for a payment. If cmd is deleted, then wait_payment()
* no longer be called.
* Return callback if we called already, otherwise NULL. */
static struct command_result *wait_payment(struct lightningd *ld,
Expand Down Expand Up @@ -555,7 +584,9 @@ static struct command_result *wait_payment(struct lightningd *ld,
"Payment failure reason unknown");
} else if (failonionreply) {
/* failed to parse returned onion error */
return sendpay_fail(cmd, PAY_UNPARSEABLE_ONION,
return sendpay_fail(cmd,
payment,
PAY_UNPARSEABLE_ONION,
failonionreply,
NULL, faildetail);
} else {
Expand All @@ -571,6 +602,7 @@ static struct command_result *wait_payment(struct lightningd *ld,
/* FIXME: We don't store this! */
fail->msg = NULL;
return sendpay_fail(cmd,
payment,
faildestperm
? PAY_DESTINATION_PERM_FAIL
: PAY_TRY_OTHER_ROUTE,
Expand Down Expand Up @@ -709,8 +741,8 @@ send_payment(struct lightningd *ld,
&route[0].channel_id,
&channel->peer->id);

return sendpay_fail(cmd, PAY_TRY_OTHER_ROUTE, NULL,
fail, "First peer not ready");
return sendpay_fail(cmd, payment, PAY_TRY_OTHER_ROUTE,
NULL, fail, "First peer not ready");
}

/* Copy channels used along the route. */
Expand Down
15 changes: 15 additions & 0 deletions lightningd/pay.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
#ifndef LIGHTNING_LIGHTNINGD_PAY_H
#define LIGHTNING_LIGHTNINGD_PAY_H
#include "config.h"
#include <ccan/short_types/short_types.h>

struct htlc_out;
struct lightningd;
struct preimage;
struct sha256;
struct json_stream;
struct wallet_payment;
struct routing_failure;

void payment_succeeded(struct lightningd *ld, struct htlc_out *hout,
const struct preimage *rval);
Expand All @@ -16,4 +20,15 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout,
/* Inform payment system to save the payment. */
void payment_store(struct lightningd *ld, const struct sha256 *payment_hash);

/* This json will be also used in 'sendpay_success' notifictaion. */
void json_add_payment_fields(struct json_stream *response,
const struct wallet_payment *t);

/* This json will be also used in 'sendpay_failure' notifictaion. */
void json_sendpay_fail_fields(struct json_stream *js,
const struct wallet_payment *t,
int pay_errcode,
const u8 *onionreply,
const struct routing_failure *fail);

#endif /* LIGHTNING_LIGHTNINGD_PAY_H */
Loading