diff --git a/contrib/plugins/helloworld.py b/contrib/plugins/helloworld.py index 3fb15ca0e..265afe511 100755 --- a/contrib/plugins/helloworld.py +++ b/contrib/plugins/helloworld.py @@ -48,6 +48,14 @@ def on_payment(plugin, invoice_payment, **kwargs): invoice_payment.get("msat"))) +@plugin.subscribe("invoice_creation") +def on_invoice_creation(plugin, invoice_creation, **kwargs): + plugin.log("Received invoice_creation event for label {}, preimage {}," + " and amount of {}".format(invoice_creation.get("label"), + invoice_creation.get("preimage"), + invoice_creation.get("msat"))) + + @plugin.hook("htlc_accepted") def on_htlc_accepted(onion, htlc, plugin, **kwargs): plugin.log('on_htlc_accepted called') diff --git a/doc/PLUGINS.md b/doc/PLUGINS.md index a57a0fcb0..fd854a230 100644 --- a/doc/PLUGINS.md +++ b/doc/PLUGINS.md @@ -334,6 +334,20 @@ A notification for topic `invoice_payment` is sent every time an invoie is paid. "msat": "10000msat" } } + +``` +### `invoice_creation` + +A notification for topic `invoice_creation` is sent every time an invoie is paid. + +```json +{ + "invoice_creation": { + "label": "unique-label-for-invoice", + "preimage": "0000000000000000000000000000000000000000000000000000000000000000", + "msat": "10000msat" + } +} ``` ### `warning` diff --git a/lightningd/invoice.c b/lightningd/invoice.c index e05f324dc..866f054f6 100644 --- a/lightningd/invoice.c +++ b/lightningd/invoice.c @@ -720,6 +720,9 @@ static void gossipd_incoming_channels_reply(struct subd *gossipd, json_add_u64(response, "expires_at", details->expiry_time); json_add_string(response, "bolt11", details->bolt11); + notify_invoice_creation(info->cmd->ld, info->b11->msat, + info->payment_preimage, info->label); + /* Warn if there's not sufficient incoming capacity. */ if (tal_count(info->b11->routes) == 0) { log_unusual(info->cmd->ld->log, diff --git a/lightningd/notification.c b/lightningd/notification.c index d2f8ca49d..59d5bde9d 100644 --- a/lightningd/notification.c +++ b/lightningd/notification.c @@ -140,6 +140,41 @@ void notify_invoice_payment(struct lightningd *ld, struct amount_msat amount, plugins_notify(ld->plugins, take(n)); } +static void invoice_creation_notification_serialize(struct json_stream *stream, + struct amount_msat *amount, + struct preimage preimage, + const struct json_escape *label) +{ + json_object_start(stream, "invoice_creation"); + if (amount != NULL) + json_add_string( + stream, "msat", + type_to_string(tmpctx, struct amount_msat, amount)); + + json_add_hex(stream, "preimage", &preimage, sizeof(preimage)); + json_add_escaped_string(stream, "label", label); + json_object_end(stream); +} + +REGISTER_NOTIFICATION(invoice_creation, + invoice_creation_notification_serialize) + +void notify_invoice_creation(struct lightningd *ld, struct amount_msat *amount, + struct preimage preimage, + const struct json_escape *label) +{ + void (*serialize)(struct json_stream *, + struct amount_msat *, + struct preimage, + const struct json_escape *) = invoice_creation_notification_gen.serialize; + + struct jsonrpc_notification *n + = jsonrpc_notification_start(NULL, invoice_creation_notification_gen.topic); + serialize(n->stream, amount, preimage, label); + jsonrpc_notification_end(n); + plugins_notify(ld->plugins, take(n)); +} + static void channel_opened_notification_serialize(struct json_stream *stream, struct node_id *node_id, struct amount_sat *funding_sat, diff --git a/lightningd/notification.h b/lightningd/notification.h index deaf9ec3c..4a7914f5f 100644 --- a/lightningd/notification.h +++ b/lightningd/notification.h @@ -47,6 +47,9 @@ void notify_warning(struct lightningd *ld, struct log_entry *l); void notify_invoice_payment(struct lightningd *ld, struct amount_msat amount, struct preimage preimage, const struct json_escape *label); +void notify_invoice_creation(struct lightningd *ld, struct amount_msat *amount, + struct preimage preimage, const struct json_escape *label); + void notify_channel_opened(struct lightningd *ld, struct node_id *node_id, struct amount_sat *funding_sat, struct bitcoin_txid *funding_txid, bool *funding_locked); diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index 0dcbb86cc..839df1603 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -246,6 +246,10 @@ void notify_connect(struct lightningd *ld UNNEEDED, struct node_id *nodeid UNNEE /* Generated stub for notify_disconnect */ void notify_disconnect(struct lightningd *ld UNNEEDED, struct node_id *nodeid UNNEEDED) { fprintf(stderr, "notify_disconnect called!\n"); abort(); } +/* Generated stub for notify_invoice_creation */ +void notify_invoice_creation(struct lightningd *ld UNNEEDED, struct amount_msat *amount UNNEEDED, + struct preimage preimage UNNEEDED, const struct json_escape *label UNNEEDED) +{ fprintf(stderr, "notify_invoice_creation called!\n"); abort(); } /* Generated stub for notify_invoice_payment */ void notify_invoice_payment(struct lightningd *ld UNNEEDED, struct amount_msat amount UNNEEDED, struct preimage preimage UNNEEDED, const struct json_escape *label UNNEEDED) diff --git a/tests/test_plugin.py b/tests/test_plugin.py index cbf324cac..acb6b5f14 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -694,6 +694,24 @@ def test_invoice_payment_notification(node_factory): .format(label, preimage, msats)) +@unittest.skipIf(not DEVELOPER, "needs to deactivate shadow routing") +def test_invoice_creation_notification(node_factory): + """ + Test the 'invoice_creation' notification + """ + opts = [{}, {"plugin": os.path.join(os.getcwd(), "contrib/plugins/helloworld.py")}] + l1, l2 = node_factory.line_graph(2, opts=opts) + + msats = 12345 + preimage = '1' * 64 + label = "a_descriptive_label" + l2.rpc.invoice(msats, label, 'description', preimage=preimage) + + l2.daemon.wait_for_log(r"Received invoice_creation event for label {}," + " preimage {}, and amount of {}msat" + .format(label, preimage, msats)) + + def test_channel_opened_notification(node_factory): """ Test the 'channel_opened' notification sent at channel funding success.