Browse Source

offers: make it a runtime option.

The fetchinvoice and offers plugins disable themselves if the option
isn't enabled (it's enabled by default on EXPERIMENTAL_FEATURES).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Added: `experimental-offers` enables fetch, payment and creation of (early draft) offers.
ppa
Rusty Russell 4 years ago
committed by Christian Decker
parent
commit
001b5d6416
  1. 2
      common/Makefile
  2. 2
      common/blindedpath.h
  3. 2
      common/json.c
  4. 7
      common/utils.h
  5. 5
      devtools/Makefile
  6. 5
      hsmd/Makefile
  7. 10
      hsmd/hsmd.c
  8. 11
      lightningd/Makefile
  9. 12
      lightningd/invoice.c
  10. 3
      lightningd/lightningd.h
  11. 16
      lightningd/options.c
  12. 16
      lightningd/pay.c
  13. 43
      lightningd/test/run-invoice-select-inchan.c
  14. 23
      plugins/Makefile
  15. 9
      plugins/fetchinvoice.c
  16. 9
      plugins/offers.c
  17. 22
      plugins/pay.c
  18. 26
      tests/test_pay.py
  19. 4
      tests/test_plugin.py
  20. 1565
      wire/bolt12_wiregen.c
  21. 319
      wire/bolt12_wiregen.h
  22. 2
      wire/common_wiregen.c
  23. 2
      wire/common_wiregen.h
  24. 2
      wire/onion_printgen.c
  25. 2
      wire/onion_printgen.h
  26. 2
      wire/onion_wiregen.c
  27. 2
      wire/onion_wiregen.h
  28. 2
      wire/peer_printgen.c
  29. 2
      wire/peer_printgen.h
  30. 2
      wire/peer_wiregen.c
  31. 2
      wire/peer_wiregen.h

2
common/Makefile

@ -9,6 +9,7 @@ COMMON_SRC_NOGEN := \
common/billboard.c \
common/bip32.c \
common/blinding.c \
common/blindedpath.c \
common/bolt11.c \
common/bolt11_json.c \
common/bolt12.c \
@ -87,7 +88,6 @@ COMMON_SRC_NOGEN := \
ifeq ($(EXPERIMENTAL_FEATURES),1)
COMMON_SRC_NOGEN += common/psbt_internal.c
COMMON_SRC_NOGEN += common/blindedpath.c
endif
COMMON_SRC_GEN := common/status_wiregen.c common/peer_status_wiregen.c

2
common/blindedpath.h

@ -3,7 +3,6 @@
#include "config.h"
#include <ccan/tal/tal.h>
#if EXPERIMENTAL_FEATURES
struct route_info;
struct pubkey;
@ -13,5 +12,4 @@ struct onionmsg_path **make_blindedpath(const tal_t *ctx,
const struct pubkey *route,
struct pubkey *initial_blinding,
struct pubkey *final_blinding);
#endif /* EXPERIMENTAL_FEATURES */
#endif /* LIGHTNING_COMMON_BLINDEDPATH_H */

2
common/json.c

@ -1198,10 +1198,8 @@ void json_add_errcode(struct json_stream *result, const char *fieldname,
void json_add_invstring(struct json_stream *result, const char *invstring)
{
#if EXPERIMENTAL_FEATURES
if (strstarts(invstring, "lni"))
json_add_string(result, "bolt12", invstring);
else
#endif
json_add_string(result, "bolt11", invstring);
}

7
common/utils.h

@ -118,6 +118,13 @@ STRUCTEQ_DEF(ripemd160, 0, u);
#define IFDEV(dev, nondev) (nondev)
#endif
#if EXPERIMENTAL_FEATURES
/* Make sure that nondev is evaluated, and valid, but is a constant */
#define IFEXPERIMENTAL(exp, nonexp) (0 ? (nonexp) : (exp))
#else
#define IFEXPERIMENTAL(exp, nonexp) (nonexp)
#endif
/* Context which all wally allocations use (see common/setup.c) */
extern const tal_t *wally_tal_ctx;

5
devtools/Makefile

@ -1,10 +1,7 @@
DEVTOOLS := devtools/bolt11-cli devtools/decodemsg devtools/onion devtools/dump-gossipstore devtools/gossipwith devtools/create-gossipstore devtools/mkcommit devtools/mkfunding devtools/mkclose devtools/mkgossip devtools/mkencoded devtools/mkquery devtools/lightning-checkmessage devtools/topology devtools/route
DEVTOOLS := devtools/bolt11-cli devtools/decodemsg devtools/onion devtools/dump-gossipstore devtools/gossipwith devtools/create-gossipstore devtools/mkcommit devtools/mkfunding devtools/mkclose devtools/mkgossip devtools/mkencoded devtools/mkquery devtools/lightning-checkmessage devtools/topology devtools/route devtools/blindedpath devtools/bolt12-cli
ifeq ($(HAVE_SQLITE3),1)
DEVTOOLS += devtools/checkchannels
endif
ifeq ($(EXPERIMENTAL_FEATURES),1)
DEVTOOLS += devtools/blindedpath devtools/bolt12-cli
endif
DEVTOOLS_TOOL_SRC := $(DEVTOOLS:=.c) devtools/print_wire.c devtools/clean_topo.c
DEVTOOLS_TOOL_OBJS := $(DEVTOOLS_TOOL_SRC:.c=.o)

5
hsmd/Makefile

@ -20,6 +20,7 @@ HSMD_COMMON_OBJS := \
common/amount.o \
common/bigsize.o \
common/bip32.o \
common/bolt12_merkle.o \
common/channel_id.o \
common/daemon.o \
common/daemon_conn.o \
@ -43,10 +44,6 @@ HSMD_COMMON_OBJS := \
common/utxo.o \
common/version.o
ifeq ($(EXPERIMENTAL_FEATURES),1)
HSMD_COMMON_OBJS += common/bolt12_merkle.o
endif
lightningd/lightning_hsmd: $(HSMD_OBJS) $(HSMD_COMMON_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS)
-include hsmd/test/Makefile

10
hsmd/hsmd.c

@ -25,9 +25,7 @@
#include <ccan/read_write_all/read_write_all.h>
#include <ccan/take/take.h>
#include <ccan/tal/str/str.h>
#if EXPERIMENTAL_FEATURES
#include <common/bolt12_merkle.h>
#endif
#include <common/daemon_conn.h>
#include <common/derive_basepoints.h>
#include <common/hash_u5.h>
@ -349,7 +347,6 @@ static void node_key(struct privkey *node_privkey, struct pubkey *node_id)
#endif
}
#if EXPERIMENTAL_FEATURES
/*~ This returns the secret and/or public x-only key for this node. */
static void node_schnorrkey(secp256k1_keypair *node_keypair,
struct pubkey32 *node_id32)
@ -374,7 +371,6 @@ static void node_schnorrkey(secp256k1_keypair *node_keypair,
"Failed to derive xonly pub");
}
}
#endif
/*~ This secret is the basis for all per-channel secrets: the per-channel seeds
* will be generated by mixing in the dbid and the peer node_id. */
@ -1842,7 +1838,6 @@ static struct io_plan *handle_sign_message(struct io_conn *conn,
take(towire_hsmd_sign_message_reply(NULL, &rsig)));
}
#if EXPERIMENTAL_FEATURES
/*~ lightningd asks us to sign a bolt12 (e.g. offer). */
static struct io_plan *handle_sign_bolt12(struct io_conn *conn,
struct client *c,
@ -1896,7 +1891,6 @@ static struct io_plan *handle_sign_bolt12(struct io_conn *conn,
return req_reply(conn, c,
take(towire_hsmd_sign_bolt12_reply(NULL, &sig)));
}
#endif
#if DEVELOPER
static struct io_plan *handle_memleak(struct io_conn *conn,
@ -2087,11 +2081,7 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c)
return handle_sign_message(conn, c, c->msg_in);
case WIRE_HSMD_SIGN_BOLT12:
#if EXPERIMENTAL_FEATURES
return handle_sign_bolt12(conn, c, c->msg_in);
#else
break;
#endif
#if DEVELOPER
case WIRE_HSMD_DEV_MEMLEAK:
return handle_memleak(conn, c, c->msg_in);

11
lightningd/Makefile

@ -45,12 +45,9 @@ LIGHTNINGD_SRC += lightningd/dual_open_control.c
endif
LIGHTNINGD_SRC_NOHDR := \
lightningd/offer.c \
lightningd/signmessage.c
ifeq ($(EXPERIMENTAL_FEATURES),1)
LIGHTNINGD_SRC_NOHDR += lightningd/offer.c
endif
LIGHTNINGD_HEADERS := \
$(LIGHTNINGD_SRC:.c=.h) \
lightningd/channel_state.h \
@ -81,6 +78,8 @@ LIGHTNINGD_COMMON_OBJS := \
common/blinding.o \
common/bolt11.o \
common/bolt11_json.o \
common/bolt12.o \
common/bolt12_merkle.o \
common/channel_id.o \
common/channel_config.o \
common/coin_mvt.o \
@ -132,10 +131,6 @@ LIGHTNINGD_COMMON_OBJS := \
common/wire_error.o \
common/wireaddr.o \
ifeq ($(EXPERIMENTAL_FEATURES),1)
LIGHTNINGD_COMMON_OBJS += common/bolt12.o common/bolt12_merkle.o
endif
include wallet/Makefile
# All together in one convenient var

12
lightningd/invoice.c

@ -8,10 +8,8 @@
#include <common/bech32.h>
#include <common/bolt11.h>
#include <common/bolt11_json.h>
#if EXPERIMENTAL_FEATURES
#include <common/bolt12.h>
#include <common/bolt12_merkle.h>
#endif
#include <common/configdir.h>
#include <common/features.h>
#include <common/json_command.h>
@ -133,7 +131,6 @@ static void invoice_secret(const struct preimage *payment_preimage,
memcpy(payment_secret->data, secret.u.u8, sizeof(secret.u.u8));
}
#if EXPERIMENTAL_FEATURES
/* FIXME: This is a hack. The real secret should be a signature of some
* onion key, using the payer_id */
static void invoice_secret_bolt12(struct lightningd *ld,
@ -156,7 +153,6 @@ static void invoice_secret_bolt12(struct lightningd *ld,
BUILD_ASSERT(sizeof(*payment_secret) == sizeof(merkle));
memcpy(payment_secret, &merkle, sizeof(merkle));
}
#endif /* EXPERIMENTAL_FEATURES */
struct invoice_payment_hook_payload {
struct lightningd *ld;
@ -371,12 +367,10 @@ invoice_check_payment(const tal_t *ctx,
if (payment_secret) {
struct secret expected;
#if EXPERIMENTAL_FEATURES
if (details->invstring && strstarts(details->invstring, "lni1"))
invoice_secret_bolt12(ld, details->invstring, &expected);
else
#endif /* EXPERIMENTAL_FEATURES */
invoice_secret(&details->r, &expected);
invoice_secret(&details->r, &expected);
if (!secret_eq_consttime(payment_secret, &expected)) {
log_debug(ld->log, "Attept to pay %s with wrong secret",
type_to_string(tmpctx, struct sha256,
@ -460,7 +454,6 @@ static bool hsm_sign_b11(const u5 *u5bytes,
return true;
}
#if EXPERIMENTAL_FEATURES
static void hsm_sign_b12_invoice(struct lightningd *ld,
struct tlv_invoice *invoice)
{
@ -481,7 +474,6 @@ static void hsm_sign_b12_invoice(struct lightningd *ld,
fatal("HSM gave bad sign_invoice_reply %s",
tal_hex(msg, msg));
}
#endif /* EXPERIMENTAL_FEATURES */
static struct command_result *parse_fallback(struct command *cmd,
const char *buffer,
@ -1505,7 +1497,6 @@ static struct command_result *json_createinvoice(struct command *cmd,
notify_invoice_creation(cmd->ld, b11->msat, *preimage, label);
} else {
#if EXPERIMENTAL_FEATURES
struct tlv_invoice *inv;
struct sha256 *local_offer_id;
@ -1574,7 +1565,6 @@ static struct command_result *json_createinvoice(struct command *cmd,
inv->amount ? &msat : NULL,
*preimage, label);
} else
#endif /* EXPERIMENTAL_FEATURES */
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Unparsable invoice '%s': %s",
invstring, fail);

3
lightningd/lightningd.h

@ -66,6 +66,9 @@ struct config {
/* How long before we give up waiting for INIT msg */
u32 connection_timeout_secs;
/* EXPERIMENTAL: offers support */
bool exp_offers;
};
typedef STRMAP(const char *) alt_subdaemon_map;

16
lightningd/options.c

@ -649,6 +649,8 @@ static const struct config testnet_config = {
/* 1 minute should be enough for anyone! */
.connection_timeout_secs = 60,
.exp_offers = IFEXPERIMENTAL(true, false),
};
/* aka. "Dude, where's my coins?" */
@ -704,6 +706,8 @@ static const struct config mainnet_config = {
/* 1 minute should be enough for anyone! */
.connection_timeout_secs = 60,
.exp_offers = IFEXPERIMENTAL(true, false),
};
static void check_config(struct lightningd *ld)
@ -807,6 +811,12 @@ static char *opt_set_onion_messages(struct lightningd *ld)
return NULL;
}
static char *opt_set_offers(struct lightningd *ld)
{
ld->config.exp_offers = true;
return opt_set_onion_messages(ld);
}
static void register_opts(struct lightningd *ld)
{
/* This happens before plugins started */
@ -859,6 +869,10 @@ static void register_opts(struct lightningd *ld)
opt_set_onion_messages, ld,
"EXPERIMENTAL: enable send, receive and relay"
" of onion messages");
opt_register_early_noarg("--experimental-offers",
opt_set_offers, ld,
"EXPERIMENTAL: enable send and receive of offers"
" (also sets experimental-onion-messages)");
opt_register_noarg("--help|-h", opt_lightningd_usage, ld,
"Print this message.");
@ -1280,6 +1294,8 @@ static void add_config(struct lightningd *ld,
feature_offered(ld->our_features
->bits[INIT_FEATURE],
OPT_ONION_MESSAGES));
} else if (opt->cb == (void *)opt_set_offers) {
json_add_bool(response, name0, ld->config.exp_offers);
} else if (opt->cb == (void *)plugin_opt_flag_set) {
/* Noop, they will get added below along with the
* OPT_HASARG options. */

16
lightningd/pay.c

@ -2,10 +2,8 @@
#include <ccan/str/hex/hex.h>
#include <ccan/tal/str/str.h>
#include <common/bolt11.h>
#if EXPERIMENTAL_FEATURES
#include <common/bolt12.h>
#include <common/bolt12_merkle.h>
#endif
#include <common/json_command.h>
#include <common/json_helpers.h>
#include <common/jsonrpc_errors.h>
@ -156,11 +154,9 @@ void json_add_payment_fields(struct json_stream *response,
if (t->label)
json_add_string(response, "label", t->label);
if (t->invstring) {
#if EXPERIMENTAL_FEATURES
if (strstarts(t->invstring, "lni"))
json_add_string(response, "bolt12", t->invstring);
else
#endif
json_add_string(response, "bolt11", t->invstring);
}
@ -344,10 +340,8 @@ void payment_succeeded(struct lightningd *ld, struct htlc_out *hout,
hout->partid);
assert(payment);
#if EXPERIMENTAL_FEATURES
if (payment->local_offer_id)
wallet_offer_mark_used(ld->wallet->db, payment->local_offer_id);
#endif
tell_waiters_success(ld, &hout->payment_hash, payment);
}
@ -803,7 +797,6 @@ static const u8 *send_onion(const tal_t *ctx, struct lightningd *ld,
&dont_care_about_channel_update);
}
#if EXPERIMENTAL_FEATURES
static struct command_result *check_offer_usage(struct command *cmd,
const struct sha256 *local_offer_id)
{
@ -855,7 +848,6 @@ static struct command_result *check_offer_usage(struct command *cmd,
return NULL;
}
#endif /* EXPERIMENTAL_FEATURES */
/* destination/route_channels/route_nodes are NULL (and path_secrets may be NULL)
* if we're sending a raw onion. */
@ -1011,12 +1003,10 @@ send_payment_core(struct lightningd *ld,
&total_msat));
}
#if EXPERIMENTAL_FEATURES
struct command_result *offer_err;
offer_err = check_offer_usage(cmd, local_offer_id);
if (offer_err)
return offer_err;
#endif
channel = active_channel_by_id(ld, &first_hop->nodeid, NULL);
if (!channel) {
@ -1296,9 +1286,7 @@ static struct command_result *json_sendonion(struct command *cmd,
p_opt("bolt11", param_string, &invstring),
p_opt_def("msatoshi", param_msat, &msat, AMOUNT_MSAT(0)),
p_opt("destination", param_node_id, &destination),
#if EXPERIMENTAL_FEATURES
p_opt("localofferid", param_sha256, &local_offer_id),
#endif
NULL))
return command_param_failed();
@ -1451,9 +1439,7 @@ static struct command_result *json_sendpay(struct command *cmd,
p_opt("bolt11", param_string, &invstring),
p_opt("payment_secret", param_secret, &payment_secret),
p_opt_def("partid", param_u64, &partid, 0),
#if EXPERIMENTAL_FEATURES
p_opt("localofferid", param_sha256, &local_offer_id),
#endif
NULL))
return command_param_failed();
@ -1582,7 +1568,6 @@ static struct command_result *json_listsendpays(struct command *cmd,
if (b11) {
rhash = &b11->payment_hash;
} else {
#if EXPERIMENTAL_FEATURES
struct tlv_invoice *b12;
b12 = invoice_decode(cmd, invstring, strlen(invstring),
@ -1591,7 +1576,6 @@ static struct command_result *json_listsendpays(struct command *cmd,
if (b12 && b12->payment_hash)
rhash = b12->payment_hash;
else
#endif
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Invalid invstring: %s", fail);
}

43
lightningd/test/run-invoice-select-inchan.c

@ -221,6 +221,23 @@ void htlc_set_fail(struct htlc_set *set UNNEEDED, const u8 *failmsg TAKES UNNEED
/* Generated stub for htlc_set_fulfill */
void htlc_set_fulfill(struct htlc_set *set UNNEEDED, const struct preimage *preimage UNNEEDED)
{ fprintf(stderr, "htlc_set_fulfill called!\n"); abort(); }
/* Generated stub for invoice_decode */
struct tlv_invoice *invoice_decode(const tal_t *ctx UNNEEDED,
const char *b12 UNNEEDED, size_t b12len UNNEEDED,
const struct feature_set *our_features UNNEEDED,
const struct chainparams *must_be_chain UNNEEDED,
char **fail UNNEEDED)
{ fprintf(stderr, "invoice_decode called!\n"); abort(); }
/* Generated stub for invoice_decode_nosig */
struct tlv_invoice *invoice_decode_nosig(const tal_t *ctx UNNEEDED,
const char *b12 UNNEEDED, size_t b12len UNNEEDED,
const struct feature_set *our_features UNNEEDED,
const struct chainparams *must_be_chain UNNEEDED,
char **fail UNNEEDED)
{ fprintf(stderr, "invoice_decode_nosig called!\n"); abort(); }
/* Generated stub for invoice_encode */
char *invoice_encode(const tal_t *ctx UNNEEDED, const struct tlv_invoice *bolt12_tlv UNNEEDED)
{ fprintf(stderr, "invoice_encode called!\n"); abort(); }
/* Generated stub for json_add_address */
void json_add_address(struct json_stream *response UNNEEDED, const char *fieldname UNNEEDED,
const struct wireaddr *addr UNNEEDED)
@ -356,6 +373,9 @@ void log_(struct log *log UNNEEDED, enum log_level level UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "log_ called!\n"); abort(); }
/* Generated stub for merkle_tlv */
void merkle_tlv(const struct tlv_field *fields UNNEEDED, struct sha256 *merkle UNNEEDED)
{ fprintf(stderr, "merkle_tlv called!\n"); abort(); }
/* Generated stub for new_bolt11 */
struct bolt11 *new_bolt11(const tal_t *ctx UNNEEDED,
const struct amount_msat *msat TAKES UNNEEDED)
@ -758,29 +778,6 @@ bool dev_disconnect_permanent(struct lightningd *ld UNNEEDED)
{ fprintf(stderr, "dev_disconnect_permanent called!\n"); abort(); }
#endif
#if EXPERIMENTAL_FEATURES
/* Generated stub for merkle_tlv */
void merkle_tlv(const struct tlv_field *fields UNNEEDED, struct sha256 *merkle UNNEEDED)
{ fprintf(stderr, "merkle_tlv called!\n"); abort(); }
/* Generated stub for invoice_decode_nosig */
struct tlv_invoice *invoice_decode_nosig(const tal_t *ctx UNNEEDED,
const char *b12 UNNEEDED, size_t b12len UNNEEDED,
const struct feature_set *our_features UNNEEDED,
const struct chainparams *must_be_chain UNNEEDED,
char **fail UNNEEDED)
{ fprintf(stderr, "invoice_decode_nosig called!\n"); abort(); }
/* Generated stub for invoice_encode */
char *invoice_encode(const tal_t *ctx UNNEEDED, const struct tlv_invoice *bolt12_tlv UNNEEDED)
{ fprintf(stderr, "invoice_encode called!\n"); abort(); }
/* Generated stub for invoice_decode */
struct tlv_invoice *invoice_decode(const tal_t *ctx UNNEEDED,
const char *b12 UNNEEDED, size_t b12len UNNEEDED,
const struct feature_set *our_features UNNEEDED,
const struct chainparams *must_be_chain UNNEEDED,
char **fail UNNEEDED)
{ fprintf(stderr, "invoice_decode called!\n"); abort(); }
#endif
static void add_candidate(struct routehint_candidate **candidates, int n,
struct channel *c)
{

23
plugins/Makefile

@ -1,10 +1,6 @@
PLUGIN_PAY_SRC := plugins/pay.c
PLUGIN_PAY_OBJS := $(PLUGIN_PAY_SRC:.c=.o)
ifeq ($(EXPERIMENTAL_FEATURES),1)
PLUGIN_PAY_EXPERIMENTAL_OBJS := common/bolt12.o common/bolt12_merkle.o wire/bolt12$(EXP)_wiregen.o bitcoin/block.o
endif
PLUGIN_AUTOCLEAN_SRC := plugins/autoclean.c
PLUGIN_AUTOCLEAN_OBJS := $(PLUGIN_AUTOCLEAN_SRC:.c=.o)
@ -50,18 +46,15 @@ PLUGIN_SPENDER_OBJS := $(PLUGIN_SPENDER_SRC:.c=.o)
PLUGIN_ALL_SRC := \
$(PLUGIN_AUTOCLEAN_SRC) \
$(PLUGIN_BCLI_SRC) \
$(PLUGIN_FETCHINVOICE_SRC) \
$(PLUGIN_KEYSEND_SRC) \
$(PLUGIN_TXPREPARE_SRC) \
$(PLUGIN_LIB_SRC) \
$(PLUGIN_OFFERS_SRC) \
$(PLUGIN_PAY_LIB_SRC) \
$(PLUGIN_PAY_SRC) \
$(PLUGIN_SPENDER_SRC)
ifeq ($(EXPERIMENTAL_FEATURES),1)
PLUGIN_ALL_SRC += $(PLUGIN_OFFERS_SRC)
PLUGIN_ALL_SRC += $(PLUGIN_FETCHINVOICE_SRC)
endif
PLUGIN_ALL_HEADER := \
$(PLUGIN_LIB_HEADER) \
$(PLUGIN_PAY_LIB_HEADER) \
@ -72,15 +65,13 @@ PLUGIN_ALL_OBJS := $(PLUGIN_ALL_SRC:.c=.o)
PLUGINS := \
plugins/autoclean \
plugins/bcli \
plugins/fetchinvoice \
plugins/keysend \
plugins/offers \
plugins/pay \
plugins/txprepare \
plugins/spenderp
ifeq ($(EXPERIMENTAL_FEATURES),1)
PLUGINS += plugins/offers plugins/fetchinvoice
endif
# Make sure these depend on everything.
ALL_C_SOURCES += $(PLUGIN_ALL_SRC)
ALL_C_HEADERS += $(PLUGIN_ALL_HEADER)
@ -127,7 +118,7 @@ PLUGIN_COMMON_OBJS := \
wire/tlvstream.o \
wire/towire.o
plugins/pay: bitcoin/chainparams.o $(PLUGIN_PAY_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_PAY_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) common/gossmap.o common/route.o common/dijkstra.o $(PLUGIN_PAY_EXPERIMENTAL_OBJS)
plugins/pay: bitcoin/chainparams.o $(PLUGIN_PAY_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_PAY_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) common/gossmap.o common/route.o common/dijkstra.o common/bolt12.o common/bolt12_merkle.o wire/bolt12$(EXP)_wiregen.o bitcoin/block.o
$(PLUGIN_PAY_OBJS): $(PLUGIN_PAY_LIB_HEADER)
plugins/autoclean: bitcoin/chainparams.o $(PLUGIN_AUTOCLEAN_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS)
@ -141,9 +132,9 @@ $(PLUGIN_KEYSEND_OBJS): $(PLUGIN_PAY_LIB_HEADER)
plugins/spenderp: bitcoin/chainparams.o bitcoin/psbt.o common/psbt_open.o $(PLUGIN_SPENDER_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS)
plugins/offers: bitcoin/chainparams.o $(PLUGIN_OFFERS_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) common/bolt12.o common/bolt12_merkle.o common/bolt11_json.o common/iso4217.o wire/bolt12_exp_wiregen.o $(WIRE_OBJS) bitcoin/block.o common/channel_id.o bitcoin/preimage.o $(JSMN_OBJS) $(CCAN_OBJS)
plugins/offers: bitcoin/chainparams.o $(PLUGIN_OFFERS_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) common/bolt12.o common/bolt12_merkle.o common/bolt11_json.o common/iso4217.o $(WIRE_OBJS) bitcoin/block.o common/channel_id.o bitcoin/preimage.o $(JSMN_OBJS) $(CCAN_OBJS)
plugins/fetchinvoice: bitcoin/chainparams.o $(PLUGIN_FETCHINVOICE_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) common/bolt12.o common/bolt12_merkle.o common/iso4217.o wire/bolt12_exp_wiregen.o $(WIRE_OBJS) bitcoin/block.o common/channel_id.o bitcoin/preimage.o $(JSMN_OBJS) $(CCAN_OBJS) common/gossmap.o common/dijkstra.o common/route.o common/blindedpath.o common/hmac.o common/blinding.o
plugins/fetchinvoice: bitcoin/chainparams.o $(PLUGIN_FETCHINVOICE_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) common/bolt12.o common/bolt12_merkle.o common/iso4217.o $(WIRE_OBJS) bitcoin/block.o common/channel_id.o bitcoin/preimage.o $(JSMN_OBJS) $(CCAN_OBJS) common/gossmap.o common/dijkstra.o common/route.o common/blindedpath.o common/hmac.o common/blinding.o
$(PLUGIN_ALL_OBJS): $(PLUGIN_LIB_HEADER)

9
plugins/fetchinvoice.c

@ -1349,10 +1349,19 @@ static const struct plugin_command commands[] = {
static const char *init(struct plugin *p, const char *buf UNUSED,
const jsmntok_t *config UNUSED)
{
bool exp_offers;
rpc_scan(p, "getinfo",
take(json_out_obj(NULL, NULL, NULL)),
"{id:%}", JSON_SCAN(json_to_node_id, &local_id));
rpc_scan(p, "listconfigs",
take(json_out_obj(NULL, "config", "experimental-offers")),
"{experimental-offers:%}",
JSON_SCAN(json_to_bool, &exp_offers));
if (!exp_offers)
return "offers not enabled in config";
return NULL;
}

9
plugins/offers.c

@ -670,6 +670,7 @@ static const char *init(struct plugin *p,
const jsmntok_t *config UNUSED)
{
struct pubkey k;
bool exp_offers;
rpc_scan(p, "getinfo",
take(json_out_obj(NULL, NULL, NULL)),
@ -679,9 +680,13 @@ static const char *init(struct plugin *p,
abort();
rpc_scan(p, "listconfigs",
take(json_out_obj(NULL, "config", "cltv-final")),
"{cltv-final:%}", JSON_SCAN(json_to_number, &cltv_final));
take(json_out_obj(NULL, NULL, NULL)),
"{cltv-final:%,experimental-offers:%}",
JSON_SCAN(json_to_number, &cltv_final),
JSON_SCAN(json_to_bool, &exp_offers));
if (!exp_offers)
return "offers not enabled in config";
return NULL;
}

22
plugins/pay.c

@ -9,10 +9,8 @@
#include <ccan/tal/str/str.h>
#include <common/amount.h>
#include <common/bolt11.h>
#if EXPERIMENTAL_FEATURES
#include <common/bolt12.h>
#include <common/bolt12_merkle.h>
#endif
#include <common/errcode.h>
#include <common/features.h>
#include <common/gossip_constants.h>
@ -31,6 +29,7 @@
/* Public key of this node. */
static struct node_id my_id;
static unsigned int maxdelay_default;
static bool exp_offers;
static bool disablempp = false;
static LIST_HEAD(pay_status);
@ -1804,10 +1803,8 @@ static struct command_result *listsendpays_done(struct command *cmd,
u32 created_at;
invstrtok = json_get_member(buf, t, "bolt11");
#if EXPERIMENTAL_FEATURES
if (!invstrtok)
invstrtok = json_get_member(buf, t, "bolt12");
#endif
hashtok = json_get_member(buf, t, "payment_hash");
createdtok = json_get_member(buf, t, "created_at");
assert(hashtok != NULL);
@ -1909,9 +1906,10 @@ static const char *init(struct plugin *p,
"{id:%}", JSON_SCAN(json_to_node_id, &my_id));
rpc_scan(p, "listconfigs",
take(json_out_obj(NULL, "config", "max-locktime-blocks")),
"{max-locktime-blocks:%}",
JSON_SCAN(json_to_number, &maxdelay_default));
take(json_out_obj(NULL, NULL, NULL)),
"{max-locktime-blocks:%,experimental-offers:%}",
JSON_SCAN(json_to_number, &maxdelay_default),
JSON_SCAN(json_to_bool, &exp_offers));
return NULL;
}
@ -1964,10 +1962,8 @@ static struct command_result *json_paymod(struct command *cmd,
struct shadow_route_data *shadow_route;
struct amount_msat *invmsat;
u64 invexpiry;
#if EXPERIMENTAL_FEATURES
struct sha256 *local_offer_id;
const struct tlv_invoice *b12;
#endif
#if DEVELOPER
bool *use_shadow;
#endif
@ -1988,9 +1984,7 @@ static struct command_result *json_paymod(struct command *cmd,
p_opt_def("maxdelay", param_number, &maxdelay,
maxdelay_default),
p_opt_def("exemptfee", param_msat, &exemptfee, AMOUNT_MSAT(5000)),
#if EXPERIMENTAL_FEATURES
p_opt("localofferid", param_sha256, &local_offer_id),
#endif
#if DEVELOPER
p_opt_def("use_shadow", param_bool, &use_shadow, true),
#endif
@ -2022,10 +2016,13 @@ static struct command_result *json_paymod(struct command *cmd,
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Invalid bolt11:"
" sets feature var_onion with no secret");
#if EXPERIMENTAL_FEATURES
} else if ((b12 = invoice_decode(cmd, b11str, strlen(b11str),
plugin_feature_set(cmd->plugin),
chainparams, &fail)) != NULL) {
if (!exp_offers)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"experimental-offers disabled");
p->features = tal_steal(p, b12->features);
if (!b12->node_id)
@ -2082,7 +2079,6 @@ static struct command_result *json_paymod(struct command *cmd,
else
invexpiry = *b12->timestamp + BOLT12_DEFAULT_REL_EXPIRY;
p->local_offer_id = tal_steal(p, local_offer_id);
#endif /* EXPERIMENTAL_FEATURES */
} else
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Invalid bolt11: %s", fail);

26
tests/test_pay.py

@ -3723,10 +3723,19 @@ def test_mpp_overload_payee(node_factory, bitcoind):
l1.rpc.pay(inv)
@unittest.skipIf(not EXPERIMENTAL_FEATURES, "offers are experimental")
@unittest.skipIf(EXPERIMENTAL_FEATURES, "this is always on with EXPERIMENTAL_FEATURES")
def test_offer_needs_option(node_factory):
"""Make sure we don't make offers without offer command"""
l1 = node_factory.get_node()
with pytest.raises(RpcError, match='Unknown command'):
l1.rpc.call('offer', {'amount': '1msat', 'description': 'test'})
with pytest.raises(RpcError, match='Unknown command'):
l1.rpc.call('fetchinvoice', {'offer': 'aaaa'})
def test_offer(node_factory, bitcoind):
plugin = os.path.join(os.path.dirname(__file__), 'plugins/currencyUSDAUD5000.py')
l1 = node_factory.get_node(options={'plugin': plugin})
l1 = node_factory.get_node(options={'plugin': plugin, 'experimental-offers': None})
bolt12tool = os.path.join(os.path.dirname(__file__), "..", "devtools", "bolt12-cli")
# Try different amount strings
@ -3885,12 +3894,13 @@ def test_offer(node_factory, bitcoind):
assert 'recurrence: every 600 seconds paywindow -10 to +600 (pay proportional)\n' in output
@unittest.skipIf(not EXPERIMENTAL_FEATURES, "offers are experimental")
def test_fetchinvoice(node_factory, bitcoind):
# We remove the conversion plugin on l3, causing it to get upset.
l1, l2, l3 = node_factory.line_graph(3, wait_for_announce=True,
opts=[{}, {},
{'allow_broken_log': True}])
opts=[{'experimental-offers': None},
{'experimental-offers': None},
{'experimental-offers': None,
'allow_broken_log': True}])
# Simple offer first.
offer1 = l3.rpc.call('offer', {'amount': '2msat',
@ -3988,7 +3998,7 @@ def test_fetchinvoice(node_factory, bitcoind):
'recurrence_label': 'test recurrence'})
# Check we can request invoice without a channel.
l4 = node_factory.get_node()
l4 = node_factory.get_node(options={'experimental-offers': None})
l4.rpc.connect(l2.info['id'], 'localhost', l2.port)
ret = l4.rpc.call('fetchinvoice', {'offer': offer3,
'recurrence_counter': 0,
@ -4062,9 +4072,9 @@ def test_pay_waitblockheight_timeout(node_factory, bitcoind):
assert len(status['pay'][0]['attempts']) == 1
@unittest.skipIf(not EXPERIMENTAL_FEATURES, "offers are experimental")
def test_sendinvoice(node_factory, bitcoind):
l1, l2 = node_factory.line_graph(2, wait_for_announce=True)
l1, l2 = node_factory.line_graph(2, wait_for_announce=True,
opts={'experimental-offers': None})
# Simple offer to send money (balances channel a little)
offer = l1.rpc.call('offerout', {'amount': '100000sat',

4
tests/test_plugin.py

@ -386,9 +386,7 @@ def test_pay_plugin(node_factory):
# Make sure usage messages are present.
msg = 'pay bolt11 [msatoshi] [label] [riskfactor] [maxfeepercent] '\
'[retry_for] [maxdelay] [exemptfee]'
if EXPERIMENTAL_FEATURES:
msg += ' [localofferid]'
'[retry_for] [maxdelay] [exemptfee] [localofferid]'
if DEVELOPER:
msg += ' [use_shadow]'
assert only_one(l1.rpc.help('pay')['help'])['command'] == msg

1565
wire/bolt12_wiregen.c

File diff suppressed because it is too large

319
wire/bolt12_wiregen.h

@ -0,0 +1,319 @@
/* This file was generated by generate-wire.py */
/* Do not modify this file! Modify the _csv file it was generated from. */
/* Original template can be found at tools/gen/header_template */
#ifndef LIGHTNING_WIRE_BOLT12_WIREGEN_H
#define LIGHTNING_WIRE_BOLT12_WIREGEN_H
#include <ccan/tal/tal.h>
#include <wire/tlvstream.h>
#include <wire/wire.h>
#include <bitcoin/short_channel_id.h>
#include <bitcoin/signature.h>
#include <bitcoin/privkey.h>
#include <common/bigsize.h>
#include <common/amount.h>
#include <common/node_id.h>
#include <bitcoin/block.h>
#include <wire/onion_wire.h>
struct blinded_path {
struct pubkey blinding;
struct onionmsg_path **path;
};
struct blinded_payinfo {
u32 fee_base_msat;
u32 fee_proportional_millionths;
u16 cltv_expiry_delta;
u8 *features;
};
struct fallback_address {
u8 version;
u8 *address;
};
struct tlv_offer_recurrence {
u8 time_unit;
u32 period;
};
struct tlv_offer_recurrence_paywindow {
u32 seconds_before;
u8 proportional_amount;
u32 seconds_after;
};
struct tlv_offer_recurrence_base {
u8 start_any_period;
u64 basetime;
};
struct tlv_offer_send_invoice {
};
struct tlv_invoice_send_invoice {
};
struct tlv_invoice_fallbacks {
struct fallback_address **fallbacks;
};
struct tlv_offer {
/* Raw fields including unknown ones. */
struct tlv_field *fields;
/* TODO The following explicit fields could just point into the
* tlv_field entries above to save on memory. */
struct bitcoin_blkid *chains;
utf8 *currency;
u64 *amount;
utf8 *description;
u8 *features;
u64 *absolute_expiry;
struct blinded_path **paths;
utf8 *vendor;
u64 *quantity_min;
u64 *quantity_max;
struct tlv_offer_recurrence *recurrence;
struct tlv_offer_recurrence_paywindow *recurrence_paywindow;
u32 *recurrence_limit;
struct tlv_offer_recurrence_base *recurrence_base;
struct pubkey32 *node_id;
struct tlv_offer_send_invoice *send_invoice;
struct sha256 *refund_for;
struct bip340sig *signature;
};
struct tlv_invoice_request {
/* Raw fields including unknown ones. */
struct tlv_field *fields;
/* TODO The following explicit fields could just point into the
* tlv_field entries above to save on memory. */
struct bitcoin_blkid *chains;
struct sha256 *offer_id;
u64 *amount;
u8 *features;
u64 *quantity;
u32 *recurrence_counter;
u32 *recurrence_start;
struct pubkey32 *payer_key;
u8 *payer_info;
struct bip340sig *recurrence_signature;
};
struct tlv_invoice {
/* Raw fields including unknown ones. */
struct tlv_field *fields;
/* TODO The following explicit fields could just point into the
* tlv_field entries above to save on memory. */
struct bitcoin_blkid *chains;
struct sha256 *offer_id;
u64 *amount;
utf8 *description;
u8 *features;
struct blinded_path **paths;
struct blinded_payinfo **blindedpay;
utf8 *vendor;
struct pubkey32 *node_id;
u64 *quantity;
struct sha256 *refund_for;
u32 *recurrence_counter;
struct tlv_invoice_send_invoice *send_invoice;
u32 *recurrence_start;
u64 *recurrence_basetime;
struct pubkey32 *payer_key;
u8 *payer_info;
u64 *timestamp;
struct sha256 *payment_hash;
u32 *relative_expiry;
u32 *cltv;
struct tlv_invoice_fallbacks *fallbacks;
struct bip340sig *refund_signature;
struct bip340sig *signature;
};
struct tlv_invoice_error {
/* Raw fields including unknown ones. */
struct tlv_field *fields;
/* TODO The following explicit fields could just point into the
* tlv_field entries above to save on memory. */
u64 *erroneous_field;
u8 *suggested_value;
utf8 *error;
};
struct tlv_offer *tlv_offer_new(const tal_t *ctx);
/**
* Deserialize a TLV stream for the offer namespace.
*
* This function will parse any TLV stream, as long as the type, length and
* value fields are formatted correctly. Fields that are not known in the
* current namespace are stored in the `fields` member. Validity can be
* checked using offer_is_valid.
*/
bool fromwire_offer(const u8 **cursor, size_t *max,
struct tlv_offer * record);
/**
* Serialize a TLV stream for the offer namespace.
*
* This function only considers known fields from the offer namespace,
* and will ignore any fields that may be stored in the `fields` member. This
* ensures that the resulting stream is valid according to
* `offer_is_valid`.
*/
void towire_offer(u8 **pptr, const struct tlv_offer *record);
/**
* Check that the TLV stream is valid.
*
* Enforces the followin validity rules:
* - Types must be in monotonic non-repeating order
* - We must understand all even types
*
* Returns false if an error was detected, otherwise returns true. If err_index
* is non-null and we detect an error it is set to the index of the first error
* detected.
*/
bool offer_is_valid(const struct tlv_offer *record,
size_t *err_index);
struct tlv_invoice_request *tlv_invoice_request_new(const tal_t *ctx);
/**
* Deserialize a TLV stream for the invoice_request namespace.
*
* This function will parse any TLV stream, as long as the type, length and
* value fields are formatted correctly. Fields that are not known in the
* current namespace are stored in the `fields` member. Validity can be
* checked using invoice_request_is_valid.
*/
bool fromwire_invoice_request(const u8 **cursor, size_t *max,
struct tlv_invoice_request * record);
/**
* Serialize a TLV stream for the invoice_request namespace.
*
* This function only considers known fields from the invoice_request namespace,
* and will ignore any fields that may be stored in the `fields` member. This
* ensures that the resulting stream is valid according to
* `invoice_request_is_valid`.
*/
void towire_invoice_request(u8 **pptr, const struct tlv_invoice_request *record);
/**
* Check that the TLV stream is valid.
*
* Enforces the followin validity rules:
* - Types must be in monotonic non-repeating order
* - We must understand all even types
*
* Returns false if an error was detected, otherwise returns true. If err_index
* is non-null and we detect an error it is set to the index of the first error
* detected.
*/
bool invoice_request_is_valid(const struct tlv_invoice_request *record,
size_t *err_index);
#define TLVS_ARRAY_SIZE_invoice_request 10
extern const struct tlv_record_type tlvs_invoice_request[];
/* Define an enum with the constants */
enum invoice_request_types {
TLV_INVOICE_REQUEST_CHAINS = 2,
TLV_INVOICE_REQUEST_OFFER_ID = 4,
TLV_INVOICE_REQUEST_AMOUNT = 8,
TLV_INVOICE_REQUEST_FEATURES = 12,
TLV_INVOICE_REQUEST_QUANTITY = 32,
TLV_INVOICE_REQUEST_RECURRENCE_COUNTER = 36,
TLV_INVOICE_REQUEST_PAYER_KEY = 38,
TLV_INVOICE_REQUEST_PAYER_INFO = 50,
TLV_INVOICE_REQUEST_RECURRENCE_START = 68,
TLV_INVOICE_REQUEST_RECURRENCE_SIGNATURE = 242,
};
struct tlv_invoice *tlv_invoice_new(const tal_t *ctx);
/**
* Deserialize a TLV stream for the invoice namespace.
*
* This function will parse any TLV stream, as long as the type, length and
* value fields are formatted correctly. Fields that are not known in the
* current namespace are stored in the `fields` member. Validity can be
* checked using invoice_is_valid.
*/
bool fromwire_invoice(const u8 **cursor, size_t *max,
struct tlv_invoice * record);
/**
* Serialize a TLV stream for the invoice namespace.
*
* This function only considers known fields from the invoice namespace,
* and will ignore any fields that may be stored in the `fields` member. This
* ensures that the resulting stream is valid according to
* `invoice_is_valid`.
*/
void towire_invoice(u8 **pptr, const struct tlv_invoice *record);
/**
* Check that the TLV stream is valid.
*
* Enforces the followin validity rules:
* - Types must be in monotonic non-repeating order
* - We must understand all even types
*
* Returns false if an error was detected, otherwise returns true. If err_index
* is non-null and we detect an error it is set to the index of the first error
* detected.
*/
bool invoice_is_valid(const struct tlv_invoice *record,
size_t *err_index);
struct tlv_invoice_error *tlv_invoice_error_new(const tal_t *ctx);
/**
* Deserialize a TLV stream for the invoice_error namespace.
*
* This function will parse any TLV stream, as long as the type, length and
* value fields are formatted correctly. Fields that are not known in the
* current namespace are stored in the `fields` member. Validity can be
* checked using invoice_error_is_valid.
*/
bool fromwire_invoice_error(const u8 **cursor, size_t *max,
struct tlv_invoice_error * record);
/**
* Serialize a TLV stream for the invoice_error namespace.
*
* This function only considers known fields from the invoice_error namespace,
* and will ignore any fields that may be stored in the `fields` member. This
* ensures that the resulting stream is valid according to
* `invoice_error_is_valid`.
*/
void towire_invoice_error(u8 **pptr, const struct tlv_invoice_error *record);
/**
* Check that the TLV stream is valid.
*
* Enforces the followin validity rules:
* - Types must be in monotonic non-repeating order
* - We must understand all even types
*
* Returns false if an error was detected, otherwise returns true. If err_index
* is non-null and we detect an error it is set to the index of the first error
* detected.
*/
bool invoice_error_is_valid(const struct tlv_invoice_error *record,
size_t *err_index);
/* SUBTYPE: BLINDED_PATH */
void towire_blinded_path(u8 **p, const struct blinded_path *blinded_path);
struct blinded_path *fromwire_blinded_path(const tal_t *ctx, const u8 **cursor, size_t *plen);
/* SUBTYPE: BLINDED_PAYINFO */
void towire_blinded_payinfo(u8 **p, const struct blinded_payinfo *blinded_payinfo);
struct blinded_payinfo *fromwire_blinded_payinfo(const tal_t *ctx, const u8 **cursor, size_t *plen);
/* SUBTYPE: FALLBACK_ADDRESS */
void towire_fallback_address(u8 **p, const struct fallback_address *fallback_address);
struct fallback_address *fromwire_fallback_address(const tal_t *ctx, const u8 **cursor, size_t *plen);
#endif /* LIGHTNING_WIRE_BOLT12_WIREGEN_H */
// SHA256STAMP:b09ebf868d0b5b9792d0054bee17d763c1243d18c419847c554c63aefb7a8548

2
wire/common_wiregen.c

@ -100,4 +100,4 @@ bool fromwire_custommsg_out(const tal_t *ctx, const void *p, u8 **msg)
fromwire_u8_array(&cursor, &plen, *msg, msg_len);
return cursor != NULL;
}
// SHA256STAMP:c97dcd31559f7a0764d6bad2a532cbe79355b4c7c17b32f60ceb810329959865
// SHA256STAMP:304c3015d0df2a9436adf3c2c96365d438781a5cf55b9ccba73a05dd7bc28a4d

2
wire/common_wiregen.h

@ -41,4 +41,4 @@ bool fromwire_custommsg_out(const tal_t *ctx, const void *p, u8 **msg);
#endif /* LIGHTNING_WIRE_COMMON_WIREGEN_H */
// SHA256STAMP:c97dcd31559f7a0764d6bad2a532cbe79355b4c7c17b32f60ceb810329959865
// SHA256STAMP:304c3015d0df2a9436adf3c2c96365d438781a5cf55b9ccba73a05dd7bc28a4d

2
wire/onion_printgen.c

@ -859,4 +859,4 @@ void printonion_wire_tlv_message(const char *tlv_name, const u8 *msg) {
printwire_tlvs(tlv_name, &msg, &plen, print_tlvs_encmsg_tlvs, ARRAY_SIZE(print_tlvs_encmsg_tlvs));
}
}
// SHA256STAMP:b6eb425ab1211e5f7a8413489527aea4565904f548e72f635e4ebce72e50cdd4
// SHA256STAMP:897accc52196e69cffeee8386a5e1af8754fe49baefd58460c788024e4e8dd6f

2
wire/onion_printgen.h

@ -58,4 +58,4 @@ void printwire_mpp_timeout(const char *fieldname, const u8 *cursor);
void printwire_onionmsg_path(const char *fieldname, const u8 **cursor, size_t *plen);
#endif /* LIGHTNING_WIRE_ONION_PRINTGEN_H */
// SHA256STAMP:b6eb425ab1211e5f7a8413489527aea4565904f548e72f635e4ebce72e50cdd4
// SHA256STAMP:897accc52196e69cffeee8386a5e1af8754fe49baefd58460c788024e4e8dd6f

2
wire/onion_wiregen.c

@ -1026,4 +1026,4 @@ bool fromwire_mpp_timeout(const void *p)
return false;
return cursor != NULL;
}
// SHA256STAMP:b6eb425ab1211e5f7a8413489527aea4565904f548e72f635e4ebce72e50cdd4
// SHA256STAMP:897accc52196e69cffeee8386a5e1af8754fe49baefd58460c788024e4e8dd6f

2
wire/onion_wiregen.h

@ -317,4 +317,4 @@ bool fromwire_mpp_timeout(const void *p);
#endif /* LIGHTNING_WIRE_ONION_WIREGEN_H */
// SHA256STAMP:b6eb425ab1211e5f7a8413489527aea4565904f548e72f635e4ebce72e50cdd4
// SHA256STAMP:897accc52196e69cffeee8386a5e1af8754fe49baefd58460c788024e4e8dd6f

2
wire/peer_printgen.c

@ -2091,4 +2091,4 @@ void printpeer_wire_tlv_message(const char *tlv_name, const u8 *msg) {
printwire_tlvs(tlv_name, &msg, &plen, print_tlvs_onion_message_tlvs, ARRAY_SIZE(print_tlvs_onion_message_tlvs));
}
}
// SHA256STAMP:3e12752fa68ecad34eca722bae0a5027b6ea71ace1d2b825c6f87613d97863d5
// SHA256STAMP:9f70670271b0856273026df920106d9c2ef2b60a1fa7c9c687e83a38d7d85a00

2
wire/peer_printgen.h

@ -72,4 +72,4 @@ void printwire_onion_message(const char *fieldname, const u8 *cursor);
void printwire_channel_update_checksums(const char *fieldname, const u8 **cursor, size_t *plen);
void printwire_channel_update_timestamps(const char *fieldname, const u8 **cursor, size_t *plen);
#endif /* LIGHTNING_WIRE_PEER_PRINTGEN_H */
// SHA256STAMP:3e12752fa68ecad34eca722bae0a5027b6ea71ace1d2b825c6f87613d97863d5
// SHA256STAMP:9f70670271b0856273026df920106d9c2ef2b60a1fa7c9c687e83a38d7d85a00

2
wire/peer_wiregen.c

@ -1717,4 +1717,4 @@ bool fromwire_channel_update_option_channel_htlc_max(const void *p, secp256k1_ec
*htlc_maximum_msat = fromwire_amount_msat(&cursor, &plen);
return cursor != NULL;
}
// SHA256STAMP:3e12752fa68ecad34eca722bae0a5027b6ea71ace1d2b825c6f87613d97863d5
// SHA256STAMP:9f70670271b0856273026df920106d9c2ef2b60a1fa7c9c687e83a38d7d85a00

2
wire/peer_wiregen.h

@ -645,4 +645,4 @@ bool fromwire_channel_update_option_channel_htlc_max(const void *p, secp256k1_ec
#endif /* LIGHTNING_WIRE_PEER_WIREGEN_H */
// SHA256STAMP:3e12752fa68ecad34eca722bae0a5027b6ea71ace1d2b825c6f87613d97863d5
// SHA256STAMP:9f70670271b0856273026df920106d9c2ef2b60a1fa7c9c687e83a38d7d85a00

Loading…
Cancel
Save