Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pay: Share channel_hints across payments and plugins #7487

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
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
20 changes: 19 additions & 1 deletion common/json_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include <bitcoin/privkey.h>
#include <bitcoin/psbt.h>
#include <bitcoin/pubkey.h>
#include <bitcoin/short_channel_id.h>
#include <bitcoin/tx.h>
#include <ccan/json_escape/json_escape.h>
#include <ccan/mem/mem.h>
Expand Down Expand Up @@ -574,6 +573,25 @@ bool json_to_short_channel_id(const char *buffer, const jsmntok_t *tok,
tok->end - tok->start, scid));
}

bool json_to_short_channel_id_dir(const char *buffer, const jsmntok_t *tok,
struct short_channel_id_dir *scidd)
{
jsmntok_t scidtok, numtok;
u32 dir;

if (!split_tok(buffer, tok, '/', &scidtok, &numtok))
return false;

if (!json_to_short_channel_id(buffer, &scidtok, &scidd->scid))
return false;

if (!json_to_u32(buffer, &numtok, &dir) || (dir > 1))
return false;

scidd->dir = dir;
return true;
}

bool json_to_txid(const char *buffer, const jsmntok_t *tok,
struct bitcoin_txid *txid)
{
Expand Down
5 changes: 5 additions & 0 deletions common/json_parse.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef LIGHTNING_COMMON_JSON_PARSE_H
#define LIGHTNING_COMMON_JSON_PARSE_H
#include "config.h"
#include <bitcoin/short_channel_id.h>
#include <ccan/crypto/sha256/sha256.h>
#include <common/coin_mvt.h>
#include <common/errcode.h>
Expand Down Expand Up @@ -110,6 +111,10 @@ bool json_to_outpoint(const char *buffer, const jsmntok_t *tok,
bool json_to_channel_id(const char *buffer, const jsmntok_t *tok,
struct channel_id *cid);

/* Extract a channel id + dir from this */
bool json_to_short_channel_id_dir(const char *buffer, const jsmntok_t *tok,
struct short_channel_id_dir *scidd);

/* Extract a coin movement 'tag' from this */
bool json_to_coin_mvt_tag(const char *buffer, const jsmntok_t *tok,
enum mvt_tag *tag);
Expand Down
11 changes: 10 additions & 1 deletion common/json_stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include <bitcoin/preimage.h>
#include <bitcoin/privkey.h>
#include <bitcoin/psbt.h>
#include <bitcoin/short_channel_id.h>
#include <bitcoin/signature.h>
#include <bitcoin/tx.h>
#include <ccan/io/io.h>
Expand Down Expand Up @@ -485,6 +484,16 @@ void json_add_short_channel_id(struct json_stream *response,
short_channel_id_outnum(scid));
}

void json_add_short_channel_id_dir(struct json_stream *response,
const char *fieldname,
struct short_channel_id_dir scidd)
{
json_add_str_fmt(response, fieldname, "%dx%dx%d/%d",
short_channel_id_blocknum(scidd.scid),
short_channel_id_txnum(scidd.scid),
short_channel_id_outnum(scidd.scid), scidd.dir);
}

static void json_add_address_fields(struct json_stream *response,
const struct wireaddr *addr,
const char *typefield)
Expand Down
6 changes: 6 additions & 0 deletions common/json_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#define LIGHTNING_COMMON_JSON_STREAM_H
#include "config.h"

#include <bitcoin/short_channel_id.h>
#define JSMN_STRICT 1
# include <external/jsmn/jsmn.h>

Expand Down Expand Up @@ -313,6 +314,11 @@ void json_add_short_channel_id(struct json_stream *response,
const char *fieldname,
struct short_channel_id id);

/* '"fieldname" : "1234:5:6/1"' */
void json_add_short_channel_id_dir(struct json_stream *response,
const char *fieldname,
struct short_channel_id_dir idd);

/* JSON serialize a network address for a node */
void json_add_address(struct json_stream *response, const char *fieldname,
const struct wireaddr *addr);
Expand Down
60 changes: 59 additions & 1 deletion plugins/libplugin-pay.c
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,58 @@ void payment_start(struct payment *p)
payment_start_at_blockheight(p, INVALID_BLOCKHEIGHT);
}

static void channel_hint_to_json(const char *name, const struct channel_hint *hint, struct json_stream *dest)
{
json_object_start(dest, name);
json_add_u32(dest, "timestamp", hint->timestamp);
json_add_short_channel_id_dir(dest, "scid", hint->scid);
json_add_amount_msat(dest, "capacity_msat", hint->estimated_capacity);
json_add_bool(dest, "enabled", hint->enabled);
json_object_end(dest);
}

/**
* Load a channel_hint from its JSON representation.
*
* @return The initialized `channel_hint` or `NULL` if we encountered a parsing
* error.
*/
/*
static struct channel_hint *channel_hint_from_json(const tal_t *ctx,
const char *buffer,
const jsmntok_t *toks)
{
const char *ret;
struct channel_hint *hint = tal(ctx, struct channel_hint);
ret = json_scan(ctx, buffer, toks,
"{timestamp:%,scid:%,capacity_msat:%,enabled:%}",
JSON_SCAN(json_to_u32, &hint->timestamp),
JSON_SCAN(json_to_short_channel_id_dir, &hint->scid),
JSON_SCAN(json_to_msat, &hint->estimated_capacity),
JSON_SCAN(json_to_bool, &hint->enabled));

if (ret != NULL)
hint = tal_free(hint);
return hint;
}
*/
/**
* Notify subscribers of the `channel_hint` topic about a changed hint
*
* We share the channel_hints across payments, and across plugins, in order
* to maximize the context they have when performing payments.
*/
static void channel_hint_notify(struct plugin *plugin,
const struct channel_hint *hint)
{
struct json_stream *js =
plugin_notification_start(plugin, "channel_hint_update");

/* The timestamp used to decay the observation over time. */
channel_hint_to_json("channel_hint", hint, js);
plugin_notification_end(plugin, js);
}

static void channel_hints_update(struct payment *p,
const struct short_channel_id scid,
int direction, bool enabled, bool local,
Expand All @@ -394,6 +446,7 @@ static void channel_hints_update(struct payment *p,
{
struct payment *root = payment_root(p);
struct channel_hint newhint;
u32 timestamp = time_now().ts.tv_sec;

/* If the channel is marked as enabled it must have an estimate. */
assert(!enabled || estimated_capacity != NULL);
Expand Down Expand Up @@ -423,7 +476,8 @@ static void channel_hints_update(struct payment *p,
modified = true;
}

if (modified)
if (modified) {
hint->timestamp = timestamp;
paymod_log(p, LOG_DBG,
"Updated a channel hint for %s: "
"enabled %s, "
Expand All @@ -433,12 +487,15 @@ static void channel_hints_update(struct payment *p,
hint->enabled ? "true" : "false",
fmt_amount_msat(tmpctx,
hint->estimated_capacity));
channel_hint_notify(p->plugin, hint);
}
return;
}
}

/* No hint found, create one. */
newhint.enabled = enabled;
newhint.timestamp = timestamp;
newhint.scid.scid = scid;
newhint.scid.dir = direction;
if (local) {
Expand All @@ -458,6 +515,7 @@ static void channel_hints_update(struct payment *p,
fmt_short_channel_id_dir(tmpctx, &newhint.scid),
newhint.enabled ? "true" : "false",
fmt_amount_msat(tmpctx, newhint.estimated_capacity));
channel_hint_notify(p->plugin, &newhint);
}

static void payment_exclude_most_expensive(struct payment *p)
Expand Down
7 changes: 7 additions & 0 deletions plugins/libplugin-pay.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ struct local_hint {
* get remove on failure. Success keeps the capacities, since the capacities
* changed due to the successful HTLCs. */
struct channel_hint {
/* The timestamp this observation was made. Used to let the
* constraint expressed by this hint decay over time, until it
* is fully relaxed, at which point we can forget about it
* (the structural information is the best we can do in that
* case).
*/
u32 timestamp;
/* The short_channel_id we're going to use when referring to
* this channel. This can either be the real scid, or the
* local alias. The `pay` algorithm doesn't really care which
Expand Down
19 changes: 0 additions & 19 deletions plugins/offers_offer.c
Original file line number Diff line number Diff line change
Expand Up @@ -352,25 +352,6 @@ static struct command_result *currency_done(struct command *cmd,
return maybe_add_path(cmd, offinfo);
}

static bool json_to_short_channel_id_dir(const char *buffer, const jsmntok_t *tok,
struct short_channel_id_dir *scidd)
{
jsmntok_t scidtok, numtok;
u32 dir;

if (!split_tok(buffer, tok, '/', &scidtok, &numtok))
return false;

if (!json_to_short_channel_id(buffer, &scidtok, &scidd->scid))
return false;

if (!json_to_u32(buffer, &numtok, &dir) || (dir > 1))
return false;

scidd->dir = dir;
return true;
}

static bool json_to_sciddir_or_pubkey(const char *buffer, const jsmntok_t *tok,
struct sciddir_or_pubkey *sciddir_or_pubkey)
{
Expand Down
1 change: 1 addition & 0 deletions plugins/pay.c
Original file line number Diff line number Diff line change
Expand Up @@ -1531,6 +1531,7 @@ static const struct plugin_command commands[] = {
static const char *notification_topics[] = {
"pay_success",
"pay_failure",
"channel_hint_update",
};

int main(int argc, char *argv[])
Expand Down
9 changes: 9 additions & 0 deletions plugins/test/run-route-calc.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ void json_add_amount_msat(struct json_stream *result UNNEEDED,
struct amount_msat msat)

{ fprintf(stderr, "json_add_amount_msat called!\n"); abort(); }
/* Generated stub for json_add_bool */
void json_add_bool(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED,
bool value UNNEEDED)
{ fprintf(stderr, "json_add_bool called!\n"); abort(); }
/* Generated stub for json_add_hex_talarr */
void json_add_hex_talarr(struct json_stream *result UNNEEDED,
const char *fieldname UNNEEDED,
Expand Down Expand Up @@ -116,6 +120,11 @@ void json_add_short_channel_id(struct json_stream *response UNNEEDED,
const char *fieldname UNNEEDED,
struct short_channel_id id UNNEEDED)
{ fprintf(stderr, "json_add_short_channel_id called!\n"); abort(); }
/* Generated stub for json_add_short_channel_id_dir */
void json_add_short_channel_id_dir(struct json_stream *response UNNEEDED,
const char *fieldname UNNEEDED,
struct short_channel_id_dir idd UNNEEDED)
{ fprintf(stderr, "json_add_short_channel_id_dir called!\n"); abort(); }
/* Generated stub for json_add_string */
void json_add_string(struct json_stream *js UNNEEDED,
const char *fieldname UNNEEDED,
Expand Down
9 changes: 9 additions & 0 deletions plugins/test/run-route-overlong.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ void json_add_amount_msat(struct json_stream *result UNNEEDED,
struct amount_msat msat)

{ fprintf(stderr, "json_add_amount_msat called!\n"); abort(); }
/* Generated stub for json_add_bool */
void json_add_bool(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED,
bool value UNNEEDED)
{ fprintf(stderr, "json_add_bool called!\n"); abort(); }
/* Generated stub for json_add_hex_talarr */
void json_add_hex_talarr(struct json_stream *result UNNEEDED,
const char *fieldname UNNEEDED,
Expand Down Expand Up @@ -113,6 +117,11 @@ void json_add_short_channel_id(struct json_stream *response UNNEEDED,
const char *fieldname UNNEEDED,
struct short_channel_id id UNNEEDED)
{ fprintf(stderr, "json_add_short_channel_id called!\n"); abort(); }
/* Generated stub for json_add_short_channel_id_dir */
void json_add_short_channel_id_dir(struct json_stream *response UNNEEDED,
const char *fieldname UNNEEDED,
struct short_channel_id_dir idd UNNEEDED)
{ fprintf(stderr, "json_add_short_channel_id_dir called!\n"); abort(); }
/* Generated stub for json_add_string */
void json_add_string(struct json_stream *js UNNEEDED,
const char *fieldname UNNEEDED,
Expand Down