Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
343a54b
common: add helpers for bitcoin blockids.
rustyrussell Apr 23, 2026
1a763b6
common/json_stream: use json_out_addstrn for better efficiency.
rustyrussell Apr 23, 2026
7028e1c
ccan: add json_escape_len in json_out_addstrn
sangbida May 1, 2026
8662ed7
libplugin: expose json_add_keypath.
rustyrussell Apr 23, 2026
a32308c
common: expose json_hex_to_be32/be64
sangbida Apr 23, 2026
2f13d87
common: extract param_string_array from xpay into common.
rustyrussell Apr 23, 2026
2797a8c
bwatch: add skeleton and makefile
sangbida Apr 23, 2026
1c343e1
bwatch: add wire format
sangbida Apr 23, 2026
4c663cb
bwatch: add typed hash tables for watches
sangbida Apr 23, 2026
c555690
bwatch: persist block history
sangbida Apr 23, 2026
7a523c4
bwatch: persist watches
sangbida Apr 23, 2026
ee3aa99
bwatch: add addwatch/delwatch helpers
sangbida Apr 23, 2026
0f353c9
bwatch: poll chain and append blocks
sangbida Apr 23, 2026
23f0469
bwatch: notify watchman on block_processed
sangbida Apr 23, 2026
e4d1a8c
bwatch: detect reorgs and roll back tip
sangbida Apr 23, 2026
279dee6
bwatch: add watch_found and watch_revert notifications
sangbida Apr 23, 2026
7051aa1
bwatch: scan blocks for scriptpubkey and outpoint matches
sangbida Apr 23, 2026
511f630
bwatch: scan blocks for scid matches
sangbida Apr 23, 2026
78a913b
bwatch: fire blockdepth notifications per block
sangbida Apr 23, 2026
e798ed9
bwatch: send chaininfo to watchman on startup
sangbida Apr 23, 2026
14c4fe0
bwatch: add scriptpubkey watch RPCs
sangbida Apr 23, 2026
79645c0
bwatch: add outpoint watch RPCs
sangbida Apr 23, 2026
1a600fa
bwatch: add scid watch RPCs
sangbida Apr 23, 2026
8bba762
bwatch: add blockdepth watch RPCs
sangbida Apr 23, 2026
1c2934e
bwatch: add listwatch RPC
sangbida Apr 23, 2026
399d468
bwatch: thread per-watch parameter through block scanning
sangbida Apr 23, 2026
82fef7f
bwatch: add rescan engine for historical blocks
sangbida Apr 23, 2026
98b0b1a
bwatch: trigger rescan when a watch is added behind tip
sangbida Apr 23, 2026
8fad385
bwatch: notify watch owners on reorg
sangbida Apr 21, 2026
954a58f
pytest: add tests for bwatch.
sangbida Apr 29, 2026
7f5fff8
doc: document bwatch-poll-interval in lightningd-config.5
sangbida Apr 29, 2026
87f58fc
tests: update cli tests to reflect bwatch rpcs
sangbida Apr 29, 2026
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
22 changes: 15 additions & 7 deletions bitcoin/block.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,16 +228,24 @@ void bitcoin_block_blkid(const struct bitcoin_block *b,
*out = b->hdr.hash;
}

static bool bitcoin_blkid_to_hex(const struct bitcoin_blkid *blockid,
char *hexstr, size_t hexstr_len)
bool bitcoin_blkid_from_hex(const char *hexstr, size_t hexstr_len,
struct bitcoin_blkid *blkid)
{
struct bitcoin_txid fake_txid;
fake_txid.shad = blockid->shad;
return bitcoin_txid_to_hex(&fake_txid, hexstr, hexstr_len);
if (!hex_decode(hexstr, hexstr_len, blkid, sizeof(*blkid)))
return false;
reverse_bytes(blkid->shad.sha.u.u8, sizeof(blkid->shad.sha.u.u8));
return true;
}

char *fmt_bitcoin_blkid(const tal_t *ctx,
const struct bitcoin_blkid *blkid)
bool bitcoin_blkid_to_hex(const struct bitcoin_blkid *blkid,
char *hexstr, size_t hexstr_len)
{
struct sha256_double rev = blkid->shad;
reverse_bytes(rev.sha.u.u8, sizeof(rev.sha.u.u8));
return hex_encode(&rev, sizeof(rev), hexstr, hexstr_len);
}

char *fmt_bitcoin_blkid(const tal_t *ctx, const struct bitcoin_blkid *blkid)
{
char *hexstr = tal_arr(ctx, char, hex_str_size(sizeof(*blkid)));

Expand Down
5 changes: 5 additions & 0 deletions bitcoin/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ void fromwire_chainparams(const u8 **cursor, size_t *max,
const struct chainparams **chainparams);
void towire_chainparams(u8 **cursor, const struct chainparams *chainparams);

bool bitcoin_blkid_from_hex(const char *hexstr, size_t hexstr_len,
struct bitcoin_blkid *blkid);
bool bitcoin_blkid_to_hex(const struct bitcoin_blkid *blkid,
char *hexstr, size_t hexstr_len);

char *fmt_bitcoin_blkid(const tal_t *ctx,
const struct bitcoin_blkid *blkid);

Expand Down
9 changes: 0 additions & 9 deletions bitcoin/test/run-bitcoin_block_from_hex.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,6 @@ static const char block[] =

STRUCTEQ_DEF(sha256_double, 0, sha);

static bool bitcoin_blkid_from_hex(const char *hexstr, size_t hexstr_len,
struct bitcoin_blkid *blockid)
{
struct bitcoin_txid fake_txid;
if (!bitcoin_txid_from_hex(hexstr, hexstr_len, &fake_txid))
return false;
blockid->shad = fake_txid.shad;
return true;
}
int main(int argc, const char *argv[])
{
struct bitcoin_blkid prev;
Expand Down
2 changes: 1 addition & 1 deletion ccan/ccan/json_out/json_out.c
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ bool json_out_addstrn(struct json_out *jout,
struct json_escape *e;

if (json_escape_needed(str, len)) {
e = json_escape(NULL, str);
e = json_escape_len(NULL, str, len);
str = e->s;
len = strlen(str);
} else
Expand Down
16 changes: 16 additions & 0 deletions common/json_param.c
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,22 @@ struct command_result *param_string_or_array(struct command *cmd, const char *na
return param_string(cmd, name, buffer, tok, &(*result)->str);
}

struct command_result *param_string_array(struct command *cmd, const char *name,
const char *buffer, const jsmntok_t *tok,
const char ***arr)
{
size_t i;
const jsmntok_t *s;

if (tok->type != JSMN_ARRAY)
return command_fail_badparam(cmd, name, buffer, tok,
"should be an array");
*arr = tal_arr(cmd, const char *, tok->size);
json_for_each_arr(i, s, tok)
(*arr)[i] = json_strdup(*arr, buffer, s);
return NULL;
}

struct command_result *param_invstring(struct command *cmd, const char *name,
const char * buffer, const jsmntok_t *tok,
const char **str)
Expand Down
5 changes: 5 additions & 0 deletions common/json_param.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,11 @@ struct command_result *param_string_or_array(struct command *cmd, const char *na
const char * buffer, const jsmntok_t *tok,
struct str_or_arr **result);

/* Array of strings */
struct command_result *param_string_array(struct command *cmd, const char *name,
const char *buffer, const jsmntok_t *tok,
const char ***arr);

/* Extract an invoice string from a generic string, strip the `lightning:`
* prefix from it if needed. */
struct command_result *param_invstring(struct command *cmd, const char *name,
Expand Down
7 changes: 7 additions & 0 deletions common/json_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,13 @@ bool json_to_txid(const char *buffer, const jsmntok_t *tok,
tok->end - tok->start, txid);
}

bool json_to_bitcoin_blkid(const char *buffer, const jsmntok_t *tok,
struct bitcoin_blkid *blkid)
{
return bitcoin_blkid_from_hex(buffer + tok->start,
tok->end - tok->start, blkid);
}

bool json_to_outpoint(const char *buffer, const jsmntok_t *tok,
struct bitcoin_outpoint *op)
{
Expand Down
4 changes: 4 additions & 0 deletions common/json_parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ bool json_to_msat(const char *buffer, const jsmntok_t *tok,
bool json_to_txid(const char *buffer, const jsmntok_t *tok,
struct bitcoin_txid *txid);

/* Extract a bitcoin blkid from this */
bool json_to_bitcoin_blkid(const char *buffer, const jsmntok_t *tok,
struct bitcoin_blkid *blkid);

/* Extract a bitcoin outpoint from this */
bool json_to_outpoint(const char *buffer, const jsmntok_t *tok,
struct bitcoin_outpoint *op);
Expand Down
13 changes: 13 additions & 0 deletions common/json_parse_simple.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "config.h"
#include <assert.h>
#include <ccan/mem/mem.h>
#include <ccan/str/hex/hex.h>
#include <ccan/tal/str/str.h>
#include <common/json_parse_simple.h>
#include <common/utils.h>
Expand Down Expand Up @@ -151,6 +152,18 @@ bool json_to_bool(const char *buffer, const jsmntok_t *tok, bool *b)
return false;
}

bool json_hex_to_be32(const char *buffer, const jsmntok_t *tok, be32 *val)
{
return hex_decode(buffer + tok->start, tok->end - tok->start,
val, sizeof(*val));
}

bool json_hex_to_be64(const char *buffer, const jsmntok_t *tok, be64 *val)
{
return hex_decode(buffer + tok->start, tok->end - tok->start,
val, sizeof(*val));
}


bool json_tok_is_num(const char *buffer, const jsmntok_t *tok)
{
Expand Down
7 changes: 7 additions & 0 deletions common/json_parse_simple.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#ifndef LIGHTNING_COMMON_JSON_PARSE_SIMPLE_H
#define LIGHTNING_COMMON_JSON_PARSE_SIMPLE_H
#include "config.h"
#include <ccan/endian/endian.h>
#include <ccan/short_types/short_types.h>
#include <ccan/tal/tal.h>

Expand Down Expand Up @@ -51,6 +52,12 @@ bool json_to_double(const char *buffer, const jsmntok_t *tok, double *num);
/* Extract boolean from this */
bool json_to_bool(const char *buffer, const jsmntok_t *tok, bool *b);

/* Extract big-endian 32-bit from hex string (for datastore) */
bool json_hex_to_be32(const char *buffer, const jsmntok_t *tok, be32 *val);

/* Extract big-endian 64-bit from hex string (for datastore) */
bool json_hex_to_be64(const char *buffer, const jsmntok_t *tok, be64 *val);

/* Is this a number? [0..9]+ */
bool json_tok_is_num(const char *buffer, const jsmntok_t *tok);

Expand Down
31 changes: 21 additions & 10 deletions common/json_stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,22 @@ void json_add_primitive(struct json_stream *js,
tal_free_if_taken(val);
}

void json_add_stringn(struct json_stream *js,
const char *fieldname,
const char *str TAKES,
size_t len)
{
if (json_filter_ok(js->filter, fieldname))
json_out_addstrn(js->jout, fieldname, str, len);
if (taken(str))
tal_free(str);
}

void json_add_string(struct json_stream *js,
const char *fieldname,
const char *str TAKES)
{
if (json_filter_ok(js->filter, fieldname))
json_out_addstr(js->jout, fieldname, str);
tal_free_if_taken(str);
json_add_stringn(js, fieldname, str, strlen(str));
}

static char *json_member_direct(struct json_stream *js,
Expand Down Expand Up @@ -298,13 +307,6 @@ void json_add_s32(struct json_stream *result, const char *fieldname,
json_add_primitive_fmt(result, fieldname, "%d", value);
}

void json_add_stringn(struct json_stream *result, const char *fieldname,
const char *value TAKES, size_t value_len)
{
json_add_str_fmt(result, fieldname, "%.*s", (int)value_len, value);
tal_free_if_taken(value);
}

void json_add_bool(struct json_stream *result, const char *fieldname, bool value)
{
json_add_primitive(result, fieldname, value ? "true" : "false");
Expand Down Expand Up @@ -455,6 +457,15 @@ void json_add_txid(struct json_stream *result, const char *fieldname,
json_add_string(result, fieldname, hex);
}

void json_add_bitcoin_blkid(struct json_stream *result, const char *fieldname,
const struct bitcoin_blkid *blkid)
{
char hex[hex_str_size(sizeof(*blkid))];

bitcoin_blkid_to_hex(blkid, hex, sizeof(hex));
json_add_string(result, fieldname, hex);
}

void json_add_outpoint(struct json_stream *result, const char *fieldname,
const struct bitcoin_outpoint *out)
{
Expand Down
5 changes: 5 additions & 0 deletions common/json_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ struct short_channel_id;
struct sha256;
struct preimage;
struct bitcoin_tx;
struct bitcoin_blkid;
struct wally_psbt;
struct lease_rates;
struct wireaddr;
Expand Down Expand Up @@ -310,6 +311,10 @@ void json_add_channel_id(struct json_stream *response,
void json_add_txid(struct json_stream *result, const char *fieldname,
const struct bitcoin_txid *txid);

/* '"fieldname" : <hexrev>' or "<hexrev>" if fieldname is NULL */
void json_add_bitcoin_blkid(struct json_stream *result, const char *fieldname,
const struct bitcoin_blkid *blkid);

/* '"fieldname" : "txid:n" */
void json_add_outpoint(struct json_stream *result, const char *fieldname,
const struct bitcoin_outpoint *out);
Expand Down
4 changes: 4 additions & 0 deletions doc/lightningd-config.5.md
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,10 @@ command, so they invoices can also be paid onchain.

The *name* is an ISO-4217 name (e.g. USD), which will be passed to *currencyrate* to fetch the exchange rate for that currency on each bookkeeper event. Setting *name* to the empty string is equivalent not setting it.

* **bwatch-poll-interval**=*MILLISECONDS* [plugin `bwatch`]

Delay between polls for new blocks from `bitcoind` (default: 30000).

### Networking options

Note that for simple setups, the implicit *autolisten* option does the
Expand Down
24 changes: 23 additions & 1 deletion plugins/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@ PLUGIN_TXPREPARE_OBJS := $(PLUGIN_TXPREPARE_SRC:.c=.o)
PLUGIN_BCLI_SRC := plugins/bcli.c
PLUGIN_BCLI_OBJS := $(PLUGIN_BCLI_SRC:.c=.o)

PLUGIN_BWATCH_SRC := plugins/bwatch/bwatch.c \
plugins/bwatch/bwatch_store.c \
plugins/bwatch/bwatch_scanner.c \
plugins/bwatch/bwatch_interface.c \
plugins/bwatch/bwatch_wiregen.c
PLUGIN_BWATCH_HEADER := plugins/bwatch/bwatch.h \
plugins/bwatch/bwatch_store.h \
plugins/bwatch/bwatch_scanner.h \
plugins/bwatch/bwatch_interface.h \
plugins/bwatch/bwatch_wiregen.h
PLUGIN_BWATCH_OBJS := $(PLUGIN_BWATCH_SRC:.c=.o)

PLUGIN_COMMANDO_SRC := plugins/commando.c
PLUGIN_COMMANDO_OBJS := $(PLUGIN_COMMANDO_SRC:.c=.o)

Expand Down Expand Up @@ -82,6 +94,7 @@ PLUGIN_ALL_SRC := \
$(PLUGIN_AUTOCLEAN_SRC) \
$(PLUGIN_chanbackup_SRC) \
$(PLUGIN_BCLI_SRC) \
$(PLUGIN_BWATCH_SRC) \
$(PLUGIN_COMMANDO_SRC) \
$(PLUGIN_FUNDER_SRC) \
$(PLUGIN_TOPOLOGY_SRC) \
Expand All @@ -102,12 +115,14 @@ PLUGIN_ALL_HEADER := \
$(PLUGIN_FUNDER_HEADER) \
$(PLUGIN_PAY_LIB_HEADER) \
$(PLUGIN_OFFERS_HEADER) \
$(PLUGIN_SPENDER_HEADER)
$(PLUGIN_SPENDER_HEADER) \
$(PLUGIN_BWATCH_HEADER)

C_PLUGINS := \
plugins/autoclean \
plugins/chanbackup \
plugins/bcli \
plugins/bwatch/bwatch \
plugins/commando \
plugins/funder \
plugins/topology \
Expand Down Expand Up @@ -185,6 +200,13 @@ plugins/exposesecret: $(PLUGIN_EXPOSESECRET_OBJS) $(PLUGIN_LIB_OBJS) libcommon.a

plugins/bcli: $(PLUGIN_BCLI_OBJS) $(PLUGIN_LIB_OBJS) libcommon.a

plugins/bwatch/bwatch.o: $(PLUGIN_BWATCH_HEADER)
plugins/bwatch/bwatch_store.o: $(PLUGIN_BWATCH_HEADER)
plugins/bwatch/bwatch_scanner.o: $(PLUGIN_BWATCH_HEADER)
plugins/bwatch/bwatch_interface.o: $(PLUGIN_BWATCH_HEADER)
plugins/bwatch/bwatch_wiregen.o: $(PLUGIN_BWATCH_HEADER)
plugins/bwatch/bwatch: $(PLUGIN_BWATCH_OBJS) $(PLUGIN_LIB_OBJS) libcommon.a

plugins/keysend: $(PLUGIN_KEYSEND_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_PAY_LIB_OBJS) libcommon.a
$(PLUGIN_KEYSEND_OBJS): $(PLUGIN_PAY_LIB_HEADER) libcommon.a

Expand Down
7 changes: 0 additions & 7 deletions plugins/bkpr/blockheights.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,6 @@ u32 find_blockheight(const struct bkpr *bkpr,
return e ? e->height : 0;
}

static bool json_hex_to_be32(const char *buffer, const jsmntok_t *tok,
be32 *val)
{
return hex_decode(buffer + tok->start, tok->end - tok->start,
val, sizeof(*val));
}

struct blockheights *init_blockheights(const tal_t *ctx,
struct command *init_cmd)
{
Expand Down
8 changes: 1 addition & 7 deletions plugins/bkpr/bookkeeper.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <common/coin_mvt.h>
#include <common/iso4217.h>
#include <common/json_param.h>
#include <common/json_parse_simple.h>
#include <common/json_stream.h>
#include <common/memleak.h>
#include <common/mkdatastorekey.h>
Expand Down Expand Up @@ -1836,13 +1837,6 @@ static const struct plugin_command commands[] = {
},
};

static bool json_hex_to_be64(const char *buffer, const jsmntok_t *tok,
be64 *val)
{
return hex_decode(buffer + tok->start, tok->end - tok->start,
val, sizeof(*val));
}

static void memleak_scan_currencyrates(struct htable *memtable,
currencymap_t *currency_rates)
{
Expand Down
Loading
Loading