From 582d310a0fb6266dbbae6c278c6e49a81c2085e9 Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Fri, 9 Sep 2022 09:48:31 -0300 Subject: [PATCH] Add plugin notification topic "block_processed". Changelog-Added: Plugins: Added notification topic "block_processed". --- doc/PLUGINS.md | 14 ++++++++++++++ lightningd/chaintopology.c | 7 ++++++- lightningd/notification.c | 27 ++++++++++++++++++++++++++ lightningd/notification.h | 4 ++++ tests/plugins/block_processed.py | 22 +++++++++++++++++++++ tests/test_plugin.py | 33 ++++++++++++++++++++++++++++++++ 6 files changed, 106 insertions(+), 1 deletion(-) create mode 100755 tests/plugins/block_processed.py diff --git a/doc/PLUGINS.md b/doc/PLUGINS.md index 7751f348abf6..5c9a99f32f9b 100644 --- a/doc/PLUGINS.md +++ b/doc/PLUGINS.md @@ -873,6 +873,20 @@ current accounts (`account_id` matches the `account_id` emitted from } ``` +### `block_processed` + +Emitted after each block is received from bitcoind, either during the initial sync or +throughout the node's life as new blocks appear. + +```json +{ + "block_processed": { + "hash": "000000000000000000034bdb3c01652a0aa8f63d32f949313d55af2509f9d245", + "height": 753304 + } +} +``` + ### `openchannel_peer_sigs` When opening a channel with a peer using the collaborative transaction protocol diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c index 9bcc27cefd5b..6ad5aa8a033c 100644 --- a/lightningd/chaintopology.c +++ b/lightningd/chaintopology.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -818,9 +819,13 @@ static void get_new_block(struct bitcoind *bitcoind, /* Unexpected predecessor? Free predecessor, refetch it. */ if (!bitcoin_blkid_eq(&topo->tip->blkid, &blk->hdr.prev_hash)) remove_tip(topo); - else + else { add_tip(topo, new_block(topo, blk, topo->tip->height + 1)); + /* tell plugins a new block was processed */ + notify_block_processed(topo->ld, topo->tip); + } + /* Try for next one. */ try_extend_tip(topo); } diff --git a/lightningd/notification.c b/lightningd/notification.c index 82ad1f616aed..0827796f97db 100644 --- a/lightningd/notification.c +++ b/lightningd/notification.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -580,6 +581,32 @@ void notify_balance_snapshot(struct lightningd *ld, plugins_notify(ld->plugins, take(n)); } +static void block_processed_notification_serialize(struct json_stream *stream, + struct block *block) +{ + json_object_start(stream, "block"); + json_add_string(stream, "hash", + type_to_string(tmpctx, struct bitcoin_blkid, &block->blkid)); + json_add_u32(stream, "height", block->height); + json_object_end(stream); +} + +REGISTER_NOTIFICATION(block_processed, + block_processed_notification_serialize); + +void notify_block_processed(struct lightningd *ld, + const struct block *block) +{ + void (*serialize)(struct json_stream *, + const struct block *block) = block_processed_notification_gen.serialize; + + struct jsonrpc_notification *n = + jsonrpc_notification_start(NULL, "block_processed"); + serialize(n->stream, block); + jsonrpc_notification_end(n); + plugins_notify(ld->plugins, take(n)); +} + static void openchannel_peer_sigs_serialize(struct json_stream *stream, const struct channel_id *cid, const struct wally_psbt *psbt) diff --git a/lightningd/notification.h b/lightningd/notification.h index 8eb00c0a3057..7a0936b0aa3f 100644 --- a/lightningd/notification.h +++ b/lightningd/notification.h @@ -2,6 +2,7 @@ #define LIGHTNING_LIGHTNINGD_NOTIFICATION_H #include "config.h" #include +#include #include #include @@ -86,6 +87,9 @@ void notify_coin_mvt(struct lightningd *ld, void notify_balance_snapshot(struct lightningd *ld, const struct balance_snapshot *snap); +void notify_block_processed(struct lightningd *ld, + const struct block *block); + void notify_openchannel_peer_sigs(struct lightningd *ld, const struct channel_id *cid, const struct wally_psbt *psbt); diff --git a/tests/plugins/block_processed.py b/tests/plugins/block_processed.py new file mode 100755 index 000000000000..f80e2bd7c40f --- /dev/null +++ b/tests/plugins/block_processed.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +from pyln.client import Plugin + + +plugin = Plugin() + +blocks_catched = [] + + +@plugin.subscribe("block_processed") +def notify_block_processed(plugin, block, **kwargs): + global blocks_catched + blocks_catched.append(block["height"]) + + +@plugin.method("blockscatched") +def return_moves(plugin): + return blocks_catched + + +plugin.run() diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 55f39f9c6312..1a739b293ad6 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -2904,3 +2904,36 @@ def test_commando_badrune(node_factory): l1.rpc.decode(base64.urlsafe_b64encode(modrune).decode('utf8')) except RpcError: pass + + +def test_block_processed_notifications(node_factory, bitcoind): + """Test if a plugin gets notifications when a new block is found""" + base = bitcoind.rpc.getblockchaininfo()["blocks"] + plugin = [ + os.path.join(os.getcwd(), "tests/plugins/block_processed.py"), + ] + l1 = node_factory.get_node(options={"plugin": plugin}) + ret = l1.rpc.call("blockscatched") + assert len(ret) == 1 and ret[0] == base + 0 + + bitcoind.generate_block(2) + sync_blockheight(bitcoind, [l1]) + ret = l1.rpc.call("blockscatched") + assert len(ret) == 3 and ret[0] == base + 0 and ret[2] == base + 2 + + l2 = node_factory.get_node(options={"plugin": plugin}) + ret = l2.rpc.call("blockscatched") + assert len(ret) == 1 and ret[0] == base + 2 + + l2.stop() + next_l2_base = bitcoind.rpc.getblockchaininfo()["blocks"] + + bitcoind.generate_block(2) + sync_blockheight(bitcoind, [l1]) + ret = l1.rpc.call("blockscatched") + assert len(ret) == 5 and ret[4] == base + 4 + + l2.start() + sync_blockheight(bitcoind, [l2]) + ret = l2.rpc.call("blockscatched") + assert len(ret) == 3 and ret[1] == next_l2_base + 1 and ret[2] == next_l2_base + 2