Browse Source

common/features: don't use internal global.

Turns out that unnecessary: all callers can access the feature_set,
so make it much more like a normal primitive.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
travis-debug
Rusty Russell 5 years ago
parent
commit
cf43e44378
  1. 13
      channeld/channeld.c
  2. 13
      common/bolt11.c
  3. 7
      common/bolt11.h
  4. 134
      common/features.c
  5. 37
      common/features.h
  6. 37
      common/test/run-bolt11.c
  7. 91
      common/test/run-features.c
  8. 18
      connectd/connectd.c
  9. 5
      connectd/peer_exchange_initmsg.c
  10. 1
      connectd/peer_exchange_initmsg.h
  11. 3
      connectd/test/run-initiator-success.c
  12. 2
      devtools/bolt11-cli.c
  13. 3
      gossipd/gossip_generation.c
  14. 4
      gossipd/gossipd.c
  15. 3
      gossipd/gossipd.h
  16. 3
      gossipd/test/run-extended-info.c
  17. 3
      gossipd/test/run-next_block_range.c
  18. 6
      lightningd/invoice.c
  19. 36
      lightningd/lightningd.c
  20. 2
      lightningd/lightningd.h
  21. 6
      lightningd/opening_control.c
  22. 25
      lightningd/options.c
  23. 2
      lightningd/pay.c
  24. 2
      lightningd/plugin.c
  25. 7
      lightningd/test/run-find_my_abspath.c
  26. 4
      lightningd/test/run-invoice-select-inchan.c
  27. 12
      openingd/openingd.c
  28. 3
      plugins/pay.c

13
channeld/channeld.c

@ -76,6 +76,9 @@ struct peer {
/* Features peer supports. */ /* Features peer supports. */
u8 *features; u8 *features;
/* Features we support. */
struct feature_set *fset;
/* Tolerable amounts for feerate (only relevant for fundee). */ /* Tolerable amounts for feerate (only relevant for fundee). */
u32 feerate_min, feerate_max; u32 feerate_min, feerate_max;
@ -415,7 +418,7 @@ static void send_announcement_signatures(struct peer *peer)
static u8 *create_channel_announcement(const tal_t *ctx, struct peer *peer) static u8 *create_channel_announcement(const tal_t *ctx, struct peer *peer)
{ {
int first, second; int first, second;
u8 *cannounce, *features = get_agreed_channelfeatures(tmpctx, peer->features); u8 *cannounce, *features = get_agreed_channelfeatures(tmpctx, peer->fset, peer->features);
if (peer->channel_direction == 0) { if (peer->channel_direction == 0) {
first = LOCAL; first = LOCAL;
@ -2325,7 +2328,7 @@ static void peer_reconnect(struct peer *peer,
bool dataloss_protect, check_extra_fields; bool dataloss_protect, check_extra_fields;
const u8 **premature_msgs = tal_arr(peer, const u8 *, 0); const u8 **premature_msgs = tal_arr(peer, const u8 *, 0);
dataloss_protect = feature_negotiated(peer->features, dataloss_protect = feature_negotiated(peer->fset, peer->features,
OPT_DATA_LOSS_PROTECT); OPT_DATA_LOSS_PROTECT);
/* Both these options give us extra fields to check. */ /* Both these options give us extra fields to check. */
@ -3045,7 +3048,6 @@ static void init_channel(struct peer *peer)
secp256k1_ecdsa_signature *remote_ann_node_sig; secp256k1_ecdsa_signature *remote_ann_node_sig;
secp256k1_ecdsa_signature *remote_ann_bitcoin_sig; secp256k1_ecdsa_signature *remote_ann_bitcoin_sig;
bool option_static_remotekey; bool option_static_remotekey;
struct feature_set *feature_set;
#if !DEVELOPER #if !DEVELOPER
bool dev_fail_process_onionpacket; /* Ignored */ bool dev_fail_process_onionpacket; /* Ignored */
#endif #endif
@ -3057,7 +3059,7 @@ static void init_channel(struct peer *peer)
msg = wire_sync_read(tmpctx, MASTER_FD); msg = wire_sync_read(tmpctx, MASTER_FD);
if (!fromwire_channel_init(peer, msg, if (!fromwire_channel_init(peer, msg,
&chainparams, &chainparams,
&feature_set, &peer->fset,
&funding_txid, &funding_txout, &funding_txid, &funding_txout,
&funding, &funding,
&minimum_depth, &minimum_depth,
@ -3113,9 +3115,6 @@ static void init_channel(struct peer *peer)
master_badmsg(WIRE_CHANNEL_INIT, msg); master_badmsg(WIRE_CHANNEL_INIT, msg);
} }
/* Now we know what features to advertize. */
features_init(take(feature_set));
/* stdin == requests, 3 == peer, 4 = gossip, 5 = gossip_store, 6 = HSM */ /* stdin == requests, 3 == peer, 4 = gossip, 5 = gossip_store, 6 = HSM */
per_peer_state_set_fds(peer->pps, 3, 4, 5); per_peer_state_set_fds(peer->pps, 3, 4, 5);

13
common/bolt11.c

@ -489,6 +489,7 @@ static void shift_bitmap_down(u8 *bitmap, size_t bits)
* See [Feature Bits](#feature-bits). * See [Feature Bits](#feature-bits).
*/ */
static char *decode_9(struct bolt11 *b11, static char *decode_9(struct bolt11 *b11,
const struct feature_set *fset,
struct hash_u5 *hu5, struct hash_u5 *hu5,
u5 **data, size_t *data_len, u5 **data, size_t *data_len,
size_t data_length) size_t data_length)
@ -511,13 +512,12 @@ static char *decode_9(struct bolt11 *b11,
* - if the `9` field contains unknown _even_ bits that are non-zero: * - if the `9` field contains unknown _even_ bits that are non-zero:
* - MUST fail the payment. * - MUST fail the payment.
*/ */
/* BOLT #11: /* We skip this check for the cli tool, which sets fset to NULL */
* The field is big-endian. The least-significant bit is numbered 0, if (fset) {
* which is _even_, and the next most significant bit is numbered 1, badf = features_unsupported(fset, b11->features, BOLT11_FEATURE);
* which is _odd_. */
badf = features_unsupported(b11->features);
if (badf != -1) if (badf != -1)
return tal_fmt(b11, "9: unknown feature bit %i", badf); return tal_fmt(b11, "9: unknown feature bit %i", badf);
}
return NULL; return NULL;
} }
@ -545,6 +545,7 @@ struct bolt11 *new_bolt11(const tal_t *ctx,
/* Decodes and checks signature; returns NULL on error. */ /* Decodes and checks signature; returns NULL on error. */
struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str, struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str,
const struct feature_set *fset,
const char *description, char **fail) const char *description, char **fail)
{ {
char *hrp, *amountstr, *prefix; char *hrp, *amountstr, *prefix;
@ -739,7 +740,7 @@ struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str,
data_length); data_length);
break; break;
case '9': case '9':
problem = decode_9(b11, &hu5, &data, &data_len, problem = decode_9(b11, fset, &hu5, &data, &data_len,
data_length); data_length);
break; break;
case 's': case 's':

7
common/bolt11.h

@ -14,6 +14,8 @@
/* We only have 10 bits for the field length, meaning < 640 bytes */ /* We only have 10 bits for the field length, meaning < 640 bytes */
#define BOLT11_FIELD_BYTE_LIMIT ((1 << 10) * 5 / 8) #define BOLT11_FIELD_BYTE_LIMIT ((1 << 10) * 5 / 8)
struct feature_set;
struct bolt11_field { struct bolt11_field {
struct list_node list; struct list_node list;
@ -74,8 +76,11 @@ struct bolt11 {
}; };
/* Decodes and checks signature; returns NULL on error; description is /* Decodes and checks signature; returns NULL on error; description is
* (optional) out-of-band description of payment, for `h` field. */ * (optional) out-of-band description of payment, for `h` field.
* fset is NULL to accept any features (usually not desirable!).
*/
struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str, struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str,
const struct feature_set *fset,
const char *description, char **fail); const char *description, char **fail);
/* Initialize an empty bolt11 struct with optional amount */ /* Initialize an empty bolt11 struct with optional amount */

134
common/features.c

@ -5,10 +5,6 @@
#include <common/utils.h> #include <common/utils.h>
#include <wire/peer_wire.h> #include <wire/peer_wire.h>
/* We keep a map of our features for each context, with the assumption that
* the init features is a superset of the others. */
static struct feature_set *our_features;
enum feature_copy_style { enum feature_copy_style {
/* Feature is not exposed (importantly, being 0, this is the default!). */ /* Feature is not exposed (importantly, being 0, this is the default!). */
FEATURE_DONT_REPRESENT, FEATURE_DONT_REPRESENT,
@ -67,84 +63,53 @@ static enum feature_copy_style feature_copy_style(u32 f, enum feature_place p)
abort(); abort();
} }
static u8 *mkfeatures(const tal_t *ctx, enum feature_place place) struct feature_set *feature_set_for_feature(const tal_t *ctx, int feature)
{ {
u8 *f = tal_arr(ctx, u8, 0); struct feature_set *fs = tal(ctx, struct feature_set);
const u8 *base = our_features->bits[INIT_FEATURE];
assert(place != INIT_FEATURE);
for (size_t i = 0; i < tal_bytelen(base)*8; i++) {
if (!feature_is_set(base, i))
continue;
switch (feature_copy_style(i, place)) { for (size_t i = 0; i < ARRAY_SIZE(fs->bits); i++) {
fs->bits[i] = tal_arr(fs, u8, 0);
switch (feature_copy_style(feature, i)) {
case FEATURE_DONT_REPRESENT: case FEATURE_DONT_REPRESENT:
continue; continue;
case FEATURE_REPRESENT: case FEATURE_REPRESENT:
set_feature_bit(&f, i); set_feature_bit(&fs->bits[i], feature);
continue; continue;
case FEATURE_REPRESENT_AS_OPTIONAL: case FEATURE_REPRESENT_AS_OPTIONAL:
set_feature_bit(&f, OPTIONAL_FEATURE(i)); set_feature_bit(&fs->bits[i], OPTIONAL_FEATURE(feature));
continue; continue;
} }
abort(); abort();
} }
return f; return fs;
} }
struct feature_set *features_core_init(const u8 *feature_bits) bool feature_set_or(struct feature_set *a,
{ const struct feature_set *b TAKES)
assert(!our_features);
our_features = notleak(tal(NULL, struct feature_set));
our_features->bits[INIT_FEATURE]
= tal_dup_talarr(our_features, u8, feature_bits);
/* Make other masks too */
for (enum feature_place f = INIT_FEATURE+1; f < NUM_FEATURE_PLACE; f++)
our_features->bits[f] = mkfeatures(our_features, f);
return our_features;
}
void features_init(struct feature_set *fset TAKES)
{
assert(!our_features);
if (taken(fset))
our_features = notleak(tal_steal(NULL, fset));
else {
our_features = notleak(tal(NULL, struct feature_set));
for (size_t i = 0; i < ARRAY_SIZE(fset->bits); i++)
our_features->bits[i] = tal_dup_talarr(our_features, u8,
fset->bits[i]);
}
}
void features_cleanup(void)
{
our_features = tal_free(our_features);
}
bool features_additional(const struct feature_set *newfset)
{ {
/* Check first, before we change anything! */ /* Check first, before we change anything! */
for (size_t i = 0; i < ARRAY_SIZE(newfset->bits); i++) { for (size_t i = 0; i < ARRAY_SIZE(b->bits); i++) {
/* FIXME: We could allow a plugin to upgrade an optional feature /* FIXME: We could allow a plugin to upgrade an optional feature
* to a compulsory one? */ * to a compulsory one? */
for (size_t b = 0; b < tal_bytelen(newfset->bits[i])*8; b++) { for (size_t j = 0; j < tal_bytelen(b->bits[i])*8; j++) {
if (feature_is_set(newfset->bits[i], b) if (feature_is_set(b->bits[i], j)
&& feature_is_set(our_features->bits[i], b)) && feature_offered(a->bits[i], j)) {
if (taken(b))
tal_free(b);
return false; return false;
} }
} }
}
for (size_t i = 0; i < ARRAY_SIZE(newfset->bits); i++) { for (size_t i = 0; i < ARRAY_SIZE(a->bits); i++) {
for (size_t b = 0; b < tal_bytelen(newfset->bits[i])*8; b++) { for (size_t j = 0; j < tal_bytelen(b->bits[i])*8; j++) {
if (feature_is_set(newfset->bits[i], b)) if (feature_is_set(b->bits[i], j))
set_feature_bit(&our_features->bits[i], b); set_feature_bit(&a->bits[i], j);
} }
} }
if (taken(b))
tal_free(b);
return true; return true;
} }
@ -172,21 +137,6 @@ static bool test_bit(const u8 *features, size_t byte, unsigned int bit)
return features[tal_count(features) - 1 - byte] & (1 << (bit % 8)); return features[tal_count(features) - 1 - byte] & (1 << (bit % 8));
} }
u8 *get_offered_nodefeatures(const tal_t *ctx)
{
return tal_dup_talarr(ctx, u8, our_features->bits[NODE_ANNOUNCE_FEATURE]);
}
u8 *get_offered_initfeatures(const tal_t *ctx)
{
return tal_dup_talarr(ctx, u8, our_features->bits[INIT_FEATURE]);
}
u8 *get_offered_globalinitfeatures(const tal_t *ctx)
{
return tal_dup_talarr(ctx, u8, our_features->bits[GLOBAL_INIT_FEATURE]);
}
static void clear_feature_bit(u8 *features, u32 bit) static void clear_feature_bit(u8 *features, u32 bit)
{ {
size_t bytenum = bit / 8, bitnum = bit % 8, len = tal_count(features); size_t bytenum = bit / 8, bitnum = bit % 8, len = tal_count(features);
@ -203,9 +153,11 @@ static void clear_feature_bit(u8 *features, u32 bit)
* - MUST set `len` to the minimum length required to hold the `features` bits * - MUST set `len` to the minimum length required to hold the `features` bits
* it sets. * it sets.
*/ */
u8 *get_agreed_channelfeatures(const tal_t *ctx, const u8 *theirfeatures) u8 *get_agreed_channelfeatures(const tal_t *ctx,
const struct feature_set *ours,
const u8 *theirfeatures)
{ {
u8 *f = tal_dup_talarr(ctx, u8, our_features->bits[CHANNEL_FEATURE]); u8 *f = tal_dup_talarr(ctx, u8, ours->bits[CHANNEL_FEATURE]);
size_t max_len = 0; size_t max_len = 0;
/* Clear any features which they didn't offer too */ /* Clear any features which they didn't offer too */
@ -225,11 +177,6 @@ u8 *get_agreed_channelfeatures(const tal_t *ctx, const u8 *theirfeatures)
return f; return f;
} }
u8 *get_offered_bolt11features(const tal_t *ctx)
{
return tal_dup_talarr(ctx, u8, our_features->bits[BOLT11_FEATURE]);
}
bool feature_is_set(const u8 *features, size_t bit) bool feature_is_set(const u8 *features, size_t bit)
{ {
size_t bytenum = bit / 8; size_t bytenum = bit / 8;
@ -246,10 +193,11 @@ bool feature_offered(const u8 *features, size_t f)
|| feature_is_set(features, OPTIONAL_FEATURE(f)); || feature_is_set(features, OPTIONAL_FEATURE(f));
} }
bool feature_negotiated(const u8 *lfeatures, size_t f) bool feature_negotiated(const struct feature_set *ours,
const u8 *lfeatures, size_t f)
{ {
return feature_offered(lfeatures, f) return feature_offered(lfeatures, f)
&& feature_offered(our_features->bits[INIT_FEATURE], f); && feature_offered(ours->bits[INIT_FEATURE], f);
} }
/** /**
@ -263,7 +211,9 @@ bool feature_negotiated(const u8 *lfeatures, size_t f)
* *
* Returns -1 on success, or first unsupported feature. * Returns -1 on success, or first unsupported feature.
*/ */
static int all_supported_features(const u8 *bitmap) static int all_supported_features(const struct feature_set *ours,
const u8 *bitmap,
enum feature_place p)
{ {
size_t len = tal_count(bitmap) * 8; size_t len = tal_count(bitmap) * 8;
@ -272,7 +222,7 @@ static int all_supported_features(const u8 *bitmap)
if (!test_bit(bitmap, bitnum/8, bitnum%8)) if (!test_bit(bitmap, bitnum/8, bitnum%8))
continue; continue;
if (feature_offered(our_features->bits[INIT_FEATURE], bitnum)) if (feature_offered(ours->bits[p], bitnum))
continue; continue;
return bitnum; return bitnum;
@ -280,15 +230,16 @@ static int all_supported_features(const u8 *bitmap)
return -1; return -1;
} }
int features_unsupported(const u8 *features) int features_unsupported(const struct feature_set *ours, const u8 *theirs,
enum feature_place p)
{ {
/* BIT 2 would logically be "compulsory initial_routing_sync", but /* BIT 2 would logically be "compulsory initial_routing_sync", but
* that does not exist, so we special case it. */ * that does not exist, so we special case it. */
if (feature_is_set(features, if (feature_is_set(theirs,
COMPULSORY_FEATURE(OPT_INITIAL_ROUTING_SYNC))) COMPULSORY_FEATURE(OPT_INITIAL_ROUTING_SYNC)))
return COMPULSORY_FEATURE(OPT_INITIAL_ROUTING_SYNC); return COMPULSORY_FEATURE(OPT_INITIAL_ROUTING_SYNC);
return all_supported_features(features); return all_supported_features(ours, theirs, p);
} }
static const char *feature_name(const tal_t *ctx, size_t f) static const char *feature_name(const tal_t *ctx, size_t f)
@ -313,12 +264,13 @@ static const char *feature_name(const tal_t *ctx, size_t f)
fnames[f / 2], (f & 1) ? "odd" : "even"); fnames[f / 2], (f & 1) ? "odd" : "even");
} }
const char **list_supported_features(const tal_t *ctx) const char **list_supported_features(const tal_t *ctx,
const struct feature_set *ours)
{ {
const char **list = tal_arr(ctx, const char *, 0); const char **list = tal_arr(ctx, const char *, 0);
for (size_t i = 0; i < tal_bytelen(our_features->bits[INIT_FEATURE]) * 8; i++) { for (size_t i = 0; i < tal_bytelen(ours->bits[INIT_FEATURE]) * 8; i++) {
if (test_bit(our_features->bits[INIT_FEATURE], i / 8, i % 8)) if (test_bit(ours->bits[INIT_FEATURE], i / 8, i % 8))
tal_arr_expand(&list, feature_name(list, i)); tal_arr_expand(&list, feature_name(list, i));
} }

37
common/features.h

@ -18,43 +18,38 @@ struct feature_set {
u8 *bits[NUM_FEATURE_PLACE]; u8 *bits[NUM_FEATURE_PLACE];
}; };
/* Initialize core features (for lightningd). */ /* Create feature set for a known feature. */
struct feature_set *features_core_init(const u8 *features TAKES); struct feature_set *feature_set_for_feature(const tal_t *ctx, int feature);
/* Initialize subdaemon features. */
void features_init(struct feature_set *fset TAKES);
/* Free feature allocations */
void features_cleanup(void);
/* Marshalling a feature set */
struct feature_set *fromwire_feature_set(const tal_t *ctx, struct feature_set *fromwire_feature_set(const tal_t *ctx,
const u8 **ptr, size_t *max); const u8 **ptr, size_t *max);
void towire_feature_set(u8 **pptr, const struct feature_set *fset); void towire_feature_set(u8 **pptr, const struct feature_set *fset);
/* Add features supplied by a plugin: returns false if we already have them */ /* a |= b, or returns false if features already in a */
bool features_additional(const struct feature_set *feature_set); bool feature_set_or(struct feature_set *a,
const struct feature_set *b TAKES);
/* Returns -1 if we're OK with all these offered features, otherwise first /* Returns -1 if we're OK with all these offered features, otherwise first
* unsupported (even) feature. */ * unsupported (even) feature. */
int features_unsupported(const u8 *features); int features_unsupported(const struct feature_set *ours, const u8 *theirs,
enum feature_place p);
/* For sending our features: tal_count() returns length. */
u8 *get_offered_initfeatures(const tal_t *ctx);
u8 *get_offered_globalinitfeatures(const tal_t *ctx);
u8 *get_offered_nodefeatures(const tal_t *ctx);
u8 *get_offered_bolt11features(const tal_t *ctx);
/* For the features in channel_announcement */ /* For the features in channel_announcement */
u8 *get_agreed_channelfeatures(const tal_t *ctx, const u8 *theirfeatures); u8 *get_agreed_channelfeatures(const tal_t *ctx,
const struct feature_set *ours,
const u8 *theirfeatures);
/* Is this feature bit requested? (Either compulsory or optional) */ /* Is this feature bit requested? (Either compulsory or optional) */
bool feature_offered(const u8 *features, size_t f); bool feature_offered(const u8 *features, size_t f);
/* Was this feature bit offered by them and us? */ /* Was this feature bit offered by them and us? */
bool feature_negotiated(const u8 *lfeatures, size_t f); bool feature_negotiated(const struct feature_set *ours,
const u8 *features, size_t f);
/* Return a list of what features we advertize. */ /* Return a list of what (init) features we advertize. */
const char **list_supported_features(const tal_t *ctx); const char **list_supported_features(const tal_t *ctx,
const struct feature_set *ours);
/* Low-level helpers to deal with big-endian bitfields. */ /* Low-level helpers to deal with big-endian bitfields. */
bool feature_is_set(const u8 *features, size_t bit); bool feature_is_set(const u8 *features, size_t bit);

37
common/test/run-bolt11.c

@ -64,7 +64,7 @@ static void test_b11(const char *b11str,
char *reproduce; char *reproduce;
struct bolt11_field *b11_extra, *expect_extra; struct bolt11_field *b11_extra, *expect_extra;
b11 = bolt11_decode(tmpctx, b11str, hashed_desc, &fail); b11 = bolt11_decode(tmpctx, b11str, NULL, hashed_desc, &fail);
if (!b11) if (!b11)
errx(1, "%s:%u:%s", __FILE__, __LINE__, fail); errx(1, "%s:%u:%s", __FILE__, __LINE__, fail);
@ -145,11 +145,11 @@ int main(void)
const char *badstr; const char *badstr;
struct bolt11_field *extra; struct bolt11_field *extra;
char *fail; char *fail;
struct feature_set *fset;
wally_init(0); wally_init(0);
secp256k1_ctx = wally_get_secp_context(); secp256k1_ctx = wally_get_secp_context();
setup_tmpctx(); setup_tmpctx();
features_core_init(NULL);
/* BOLT #11: /* BOLT #11:
* *
@ -268,7 +268,7 @@ int main(void)
for (size_t i = 0; i <= strlen(badstr); i++) { for (size_t i = 0; i <= strlen(badstr); i++) {
if (bolt11_decode(tmpctx, tal_strndup(tmpctx, badstr, i), if (bolt11_decode(tmpctx, tal_strndup(tmpctx, badstr, i),
NULL, &fail)) NULL, NULL, &fail))
abort(); abort();
assert(strstr(fail, "Bad bech32") assert(strstr(fail, "Bad bech32")
|| strstr(fail, "Invoices must start with ln")); || strstr(fail, "Invoices must start with ln"));
@ -461,9 +461,23 @@ int main(void)
set_feature_bit(&b11->features, 100); set_feature_bit(&b11->features, 100);
badstr = bolt11_encode(tmpctx, b11, false, test_sign, NULL); badstr = bolt11_encode(tmpctx, b11, false, test_sign, NULL);
assert(streq(badstr, "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q4psqqqqqqqqqqqqqqqpqsqq40wa3khl49yue3zsgm26jrepqr2eghqlx86rttutve3ugd05em86nsefzh4pfurpd9ek9w2vp95zxqnfe2u7ckudyahsa52q66tgzcp6t2dyk")); assert(streq(badstr, "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q4psqqqqqqqqqqqqqqqpqsqq40wa3khl49yue3zsgm26jrepqr2eghqlx86rttutve3ugd05em86nsefzh4pfurpd9ek9w2vp95zxqnfe2u7ckudyahsa52q66tgzcp6t2dyk"));
assert(!bolt11_decode(tmpctx, badstr, NULL, &fail)); /* Empty set of allowed bits, ensures this fails! */
fset = tal(tmpctx, struct feature_set);
fset->bits[BOLT11_FEATURE] = tal_arr(fset, u8, 0);
assert(!bolt11_decode(tmpctx, badstr, fset, NULL, &fail));
assert(streq(fail, "9: unknown feature bit 100")); assert(streq(fail, "9: unknown feature bit 100"));
/* We'd actually allow this if we either (1) don't check, or (2) accept that feature in
* either compulsory or optional forms. */
assert(bolt11_decode(tmpctx, badstr, NULL, NULL, &fail));
set_feature_bit(&fset->bits[BOLT11_FEATURE], 100);
assert(bolt11_decode(tmpctx, badstr, fset, NULL,&fail));
clear_feature_bit(fset->bits[BOLT11_FEATURE], 100);
set_feature_bit(&fset->bits[BOLT11_FEATURE], 101);
assert(bolt11_decode(tmpctx, badstr, fset, NULL, &fail));
/* BOLT-1fbccd30bb503203e4a255de67f9adb504563425 #11: /* BOLT-1fbccd30bb503203e4a255de67f9adb504563425 #11:
* *
* > ### Please send 0.00967878534 BTC for a list of items within one week, amount in pico-BTC * > ### Please send 0.00967878534 BTC for a list of items within one week, amount in pico-BTC
@ -527,53 +541,52 @@ int main(void)
* > ### Bech32 checksum is invalid. * > ### Bech32 checksum is invalid.
* > lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrnt * > lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrnt
*/ */
assert(!bolt11_decode(tmpctx, "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrnt", NULL, &fail)); assert(!bolt11_decode(tmpctx, "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrnt", NULL, NULL, &fail));
assert(streq(fail, "Bad bech32 string")); assert(streq(fail, "Bad bech32 string"));
/* BOLT-4e228a7fb4ea78af914d1ce82a63cbce8026279e #11: /* BOLT-4e228a7fb4ea78af914d1ce82a63cbce8026279e #11:
* > ### Malformed bech32 string (no 1) * > ### Malformed bech32 string (no 1)
* > pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny * > pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny
*/ */
assert(!bolt11_decode(tmpctx, "pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny", NULL, &fail)); assert(!bolt11_decode(tmpctx, "pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny", NULL, NULL, &fail));
assert(streq(fail, "Bad bech32 string")); assert(streq(fail, "Bad bech32 string"));
/* BOLT-4e228a7fb4ea78af914d1ce82a63cbce8026279e #11: /* BOLT-4e228a7fb4ea78af914d1ce82a63cbce8026279e #11:
* > ### Malformed bech32 string (mixed case) * > ### Malformed bech32 string (mixed case)
* > LNBC2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny * > LNBC2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny
*/ */
assert(!bolt11_decode(tmpctx, "LNBC2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny", NULL, &fail)); assert(!bolt11_decode(tmpctx, "LNBC2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny", NULL, NULL, &fail));
assert(streq(fail, "Bad bech32 string")); assert(streq(fail, "Bad bech32 string"));
/* BOLT-4e228a7fb4ea78af914d1ce82a63cbce8026279e #11: /* BOLT-4e228a7fb4ea78af914d1ce82a63cbce8026279e #11:
* > ### Signature is not recoverable. * > ### Signature is not recoverable.
* > lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaxtrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspk28uwq * > lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaxtrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspk28uwq
*/ */
assert(!bolt11_decode(tmpctx, "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaxtrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspk28uwq", NULL, &fail)); assert(!bolt11_decode(tmpctx, "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaxtrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspk28uwq", NULL, NULL, &fail));
assert(streq(fail, "signature recovery failed")); assert(streq(fail, "signature recovery failed"));
/* BOLT-4e228a7fb4ea78af914d1ce82a63cbce8026279e #11: /* BOLT-4e228a7fb4ea78af914d1ce82a63cbce8026279e #11:
* > ### String is too short. * > ### String is too short.
* > lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6na6hlh * > lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6na6hlh
*/ */
assert(!bolt11_decode(tmpctx, "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6na6hlh", NULL, &fail)); assert(!bolt11_decode(tmpctx, "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6na6hlh", NULL, NULL, &fail));
/* BOLT-4e228a7fb4ea78af914d1ce82a63cbce8026279e #11: /* BOLT-4e228a7fb4ea78af914d1ce82a63cbce8026279e #11:
* > ### Invalid multiplier * > ### Invalid multiplier
* > lnbc2500x1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpujr6jxr9gq9pv6g46y7d20jfkegkg4gljz2ea2a3m9lmvvr95tq2s0kvu70u3axgelz3kyvtp2ywwt0y8hkx2869zq5dll9nelr83zzqqpgl2zg * > lnbc2500x1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpujr6jxr9gq9pv6g46y7d20jfkegkg4gljz2ea2a3m9lmvvr95tq2s0kvu70u3axgelz3kyvtp2ywwt0y8hkx2869zq5dll9nelr83zzqqpgl2zg
*/ */
assert(!bolt11_decode(tmpctx, "lnbc2500x1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpujr6jxr9gq9pv6g46y7d20jfkegkg4gljz2ea2a3m9lmvvr95tq2s0kvu70u3axgelz3kyvtp2ywwt0y8hkx2869zq5dll9nelr83zzqqpgl2zg", NULL, &fail)); assert(!bolt11_decode(tmpctx, "lnbc2500x1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpujr6jxr9gq9pv6g46y7d20jfkegkg4gljz2ea2a3m9lmvvr95tq2s0kvu70u3axgelz3kyvtp2ywwt0y8hkx2869zq5dll9nelr83zzqqpgl2zg", NULL, NULL, &fail));
assert(streq(fail, "Invalid amount postfix 'x'")); assert(streq(fail, "Invalid amount postfix 'x'"));
/* BOLT- #11: /* BOLT- #11:
* > ### Invalid sub-millisatoshi precision. * > ### Invalid sub-millisatoshi precision.
* > lnbc2500000001p1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpu7hqtk93pkf7sw55rdv4k9z2vj050rxdr6za9ekfs3nlt5lr89jqpdmxsmlj9urqumg0h9wzpqecw7th56tdms40p2ny9q4ddvjsedzcplva53s * > lnbc2500000001p1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpu7hqtk93pkf7sw55rdv4k9z2vj050rxdr6za9ekfs3nlt5lr89jqpdmxsmlj9urqumg0h9wzpqecw7th56tdms40p2ny9q4ddvjsedzcplva53s
*/ */
assert(!bolt11_decode(tmpctx, "lnbc2500000001p1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpu7hqtk93pkf7sw55rdv4k9z2vj050rxdr6za9ekfs3nlt5lr89jqpdmxsmlj9urqumg0h9wzpqecw7th56tdms40p2ny9q4ddvjsedzcplva53s", NULL, &fail)); assert(!bolt11_decode(tmpctx, "lnbc2500000001p1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpu7hqtk93pkf7sw55rdv4k9z2vj050rxdr6za9ekfs3nlt5lr89jqpdmxsmlj9urqumg0h9wzpqecw7th56tdms40p2ny9q4ddvjsedzcplva53s", NULL, NULL, &fail));
assert(streq(fail, "Invalid sub-millisatoshi amount '2500000001p'")); assert(streq(fail, "Invalid sub-millisatoshi amount '2500000001p'"));
/* FIXME: Test the others! */ /* FIXME: Test the others! */
wally_cleanup(0); wally_cleanup(0);
tal_free(tmpctx); tal_free(tmpctx);
features_cleanup();
return 0; return 0;
} }

91
common/test/run-features.c

@ -65,32 +65,70 @@ static void test_featurebits_or(void)
memeq(result, tal_bytelen(result), control, tal_bytelen(control))); memeq(result, tal_bytelen(result), control, tal_bytelen(control)));
} }
static void setup_features(void) static bool feature_set_eq(const struct feature_set *f1,
const struct feature_set *f2)
{ {
static const u32 default_features[] = { /* We assume minimal sizing */
OPTIONAL_FEATURE(OPT_DATA_LOSS_PROTECT), for (size_t i = 0; i < ARRAY_SIZE(f1->bits); i++) {
OPTIONAL_FEATURE(OPT_UPFRONT_SHUTDOWN_SCRIPT), if (!memeq(f1->bits[i], tal_bytelen(f1->bits[i]),
OPTIONAL_FEATURE(OPT_GOSSIP_QUERIES), f2->bits[i], tal_bytelen(f2->bits[i])))
OPTIONAL_FEATURE(OPT_VAR_ONION), return false;
OPTIONAL_FEATURE(OPT_PAYMENT_SECRET), }
OPTIONAL_FEATURE(OPT_BASIC_MPP), return true;
OPTIONAL_FEATURE(OPT_GOSSIP_QUERIES_EX), }
OPTIONAL_FEATURE(OPT_STATIC_REMOTEKEY),
}; static void test_feature_set_or(void)
u8 *f = tal_arr(NULL, u8, 0); {
for (size_t i = 0; i < ARRAY_SIZE(default_features); i++) struct feature_set *f1, *f2, *control;
set_feature_bit(&f, default_features[i]);
features_core_init(take(f)); for (size_t i = 0; i < ARRAY_SIZE(f1->bits); i++) {
f1 = talz(tmpctx, struct feature_set);
f2 = talz(tmpctx, struct feature_set);
control = talz(tmpctx, struct feature_set);
f1->bits[i] = tal_arr(f1, u8, 0);
f2->bits[i] = tal_arr(f2, u8, 0);
control->bits[i] = tal_arr(control, u8, 0);
/* or with nothing is a nop */
set_feature_bit(&f1->bits[i], 0);
set_feature_bit(&control->bits[i], 0);
assert(feature_set_or(f1, f2));
assert(feature_set_eq(f1, control));
/* or compulsory with either compulsory or optional is a fail */
set_feature_bit(&f2->bits[i], 0);
assert(!feature_set_or(f1, f2));
assert(feature_set_eq(f1, control));
assert(!feature_set_or(f2, f1));
clear_feature_bit(f2->bits[i], 0);
set_feature_bit(&f2->bits[i], 1);
assert(!feature_set_or(f1, f2));
assert(feature_set_eq(f1, control));
assert(!feature_set_or(f2, f1));
clear_feature_bit(f2->bits[i], 1);
set_feature_bit(&f2->bits[i], 10);
set_feature_bit(&control->bits[i], 10);
assert(feature_set_or(f1, f2));
assert(feature_set_eq(f1, control));
}
} }
int main(void) int main(void)
{ {
u8 *bits, *lf; u8 *bits;
struct feature_set *fset;
setup_locale(); setup_locale();
wally_init(0); wally_init(0);
secp256k1_ctx = wally_get_secp_context(); secp256k1_ctx = wally_get_secp_context();
setup_tmpctx(); setup_tmpctx();
setup_features();
/* Just some bits to set. */
fset = feature_set_for_feature(tmpctx,
OPTIONAL_FEATURE(OPT_DATA_LOSS_PROTECT));
bits = tal_arr(tmpctx, u8, 0); bits = tal_arr(tmpctx, u8, 0);
for (size_t i = 0; i < 100; i += 3) for (size_t i = 0; i < 100; i += 3)
@ -136,38 +174,37 @@ int main(void)
/* We always support no features. */ /* We always support no features. */
memset(bits, 0, tal_count(bits)); memset(bits, 0, tal_count(bits));
assert(features_unsupported(bits) == -1); assert(features_unsupported(fset, bits, INIT_FEATURE) == -1);
/* We must support our own features. */ /* We must support our own features. */
lf = get_offered_initfeatures(tmpctx); assert(features_unsupported(fset, fset->bits[INIT_FEATURE], INIT_FEATURE) == -1);
assert(features_unsupported(lf) == -1);
/* We can add random odd features, no problem. */ /* We can add random odd features, no problem. */
for (size_t i = 1; i < 16; i += 2) { for (size_t i = 1; i < 16; i += 2) {
bits = tal_dup_talarr(tmpctx, u8, lf); bits = tal_dup_talarr(tmpctx, u8, fset->bits[INIT_FEATURE]);
set_feature_bit(&bits, i); set_feature_bit(&bits, i);
assert(features_unsupported(bits) == -1); assert(features_unsupported(fset, bits, INIT_FEATURE) == -1);
} }
/* We can't add random even features. */ /* We can't add random even features. */
for (size_t i = 0; i < 16; i += 2) { for (size_t i = 0; i < 16; i += 2) {
bits = tal_dup_talarr(tmpctx, u8, lf); bits = tal_dup_talarr(tmpctx, u8, fset->bits[INIT_FEATURE]);
set_feature_bit(&bits, i); set_feature_bit(&bits, i);
/* Special case for missing compulsory feature */ /* Special case for missing compulsory feature */
if (i == 2) { if (i == 2) {
assert(features_unsupported(bits) == i); assert(features_unsupported(fset, bits, INIT_FEATURE) == i);
} else { } else {
assert((features_unsupported(bits) == -1) assert((features_unsupported(fset, bits, INIT_FEATURE) == -1)
== feature_offered(our_features->bits[INIT_FEATURE], i)); == feature_offered(fset->bits[INIT_FEATURE], i));
} }
} }
test_featurebits_or(); test_featurebits_or();
test_feature_set_or();
wally_cleanup(0); wally_cleanup(0);
tal_free(tmpctx); tal_free(tmpctx);
take_cleanup(); take_cleanup();
features_cleanup();
return 0; return 0;
} }

18
connectd/connectd.c

@ -154,6 +154,9 @@ struct daemon {
/* Allow to define the default behavior of tor services calls*/ /* Allow to define the default behavior of tor services calls*/
bool use_v3_autotor; bool use_v3_autotor;
/* Our features, as lightningd told us */
struct feature_set *fset;
}; };
/* Peers we're trying to reach: we iterate through addrs until we succeed /* Peers we're trying to reach: we iterate through addrs until we succeed
@ -300,7 +303,7 @@ static bool get_gossipfds(struct daemon *daemon,
/*~ The way features generally work is that both sides need to offer it; /*~ The way features generally work is that both sides need to offer it;
* we always offer `gossip_queries`, but this check is explicit. */ * we always offer `gossip_queries`, but this check is explicit. */
gossip_queries_feature gossip_queries_feature
= feature_negotiated(features, OPT_GOSSIP_QUERIES); = feature_negotiated(daemon->fset, features, OPT_GOSSIP_QUERIES);
/*~ `initial_routing_sync` is supported by every node, since it was in /*~ `initial_routing_sync` is supported by every node, since it was in
* the initial lightning specification: it means the peer wants the * the initial lightning specification: it means the peer wants the
@ -436,7 +439,7 @@ struct io_plan *peer_connected(struct io_conn *conn,
* - upon receiving unknown _even_ feature bits that are non-zero: * - upon receiving unknown _even_ feature bits that are non-zero:
* - MUST fail the connection. * - MUST fail the connection.
*/ */
unsup = features_unsupported(features); unsup = features_unsupported(daemon->fset, features, INIT_FEATURE);
if (unsup != -1) { if (unsup != -1) {
msg = towire_errorfmt(NULL, NULL, "Unsupported feature %u", msg = towire_errorfmt(NULL, NULL, "Unsupported feature %u",
unsup); unsup);
@ -490,7 +493,7 @@ static struct io_plan *handshake_in_success(struct io_conn *conn,
struct node_id id; struct node_id id;
node_id_from_pubkey(&id, id_key); node_id_from_pubkey(&id, id_key);
status_peer_debug(&id, "Connect IN"); status_peer_debug(&id, "Connect IN");
return peer_exchange_initmsg(conn, daemon, cs, &id, addr); return peer_exchange_initmsg(conn, daemon, daemon->fset, cs, &id, addr);
} }
/*~ When we get a connection in we set up its network address then call /*~ When we get a connection in we set up its network address then call
@ -550,7 +553,8 @@ static struct io_plan *handshake_out_success(struct io_conn *conn,
node_id_from_pubkey(&id, key); node_id_from_pubkey(&id, key);
connect->connstate = "Exchanging init messages"; connect->connstate = "Exchanging init messages";
status_peer_debug(&id, "Connect OUT"); status_peer_debug(&id, "Connect OUT");
return peer_exchange_initmsg(conn, connect->daemon, cs, &id, addr); return peer_exchange_initmsg(conn, connect->daemon,
connect->daemon->fset, cs, &id, addr);
} }
struct io_plan *connection_out(struct io_conn *conn, struct connecting *connect) struct io_plan *connection_out(struct io_conn *conn, struct connecting *connect)
@ -1201,14 +1205,13 @@ static struct io_plan *connect_init(struct io_conn *conn,
struct wireaddr_internal *proposed_wireaddr; struct wireaddr_internal *proposed_wireaddr;
enum addr_listen_announce *proposed_listen_announce; enum addr_listen_announce *proposed_listen_announce;
struct wireaddr *announcable; struct wireaddr *announcable;
struct feature_set *feature_set;
char *tor_password; char *tor_password;
/* Fields which require allocation are allocated off daemon */ /* Fields which require allocation are allocated off daemon */
if (!fromwire_connectctl_init( if (!fromwire_connectctl_init(
daemon, msg, daemon, msg,
&chainparams, &chainparams,
&feature_set, &daemon->fset,
&daemon->id, &daemon->id,
&proposed_wireaddr, &proposed_wireaddr,
&proposed_listen_announce, &proposed_listen_announce,
@ -1221,9 +1224,6 @@ static struct io_plan *connect_init(struct io_conn *conn,
master_badmsg(WIRE_CONNECTCTL_INIT, msg); master_badmsg(WIRE_CONNECTCTL_INIT, msg);
} }
/* Now we know what features to advertize. */
features_init(take(feature_set));
if (!pubkey_from_node_id(&daemon->mykey, &daemon->id)) if (!pubkey_from_node_id(&daemon->mykey, &daemon->id))
status_failed(STATUS_FAIL_INTERNAL_ERROR, status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Invalid id for me %s", "Invalid id for me %s",

5
connectd/peer_exchange_initmsg.c

@ -135,6 +135,7 @@ static struct io_plan *peer_write_postclose(struct io_conn *conn,
struct io_plan *peer_exchange_initmsg(struct io_conn *conn, struct io_plan *peer_exchange_initmsg(struct io_conn *conn,
struct daemon *daemon, struct daemon *daemon,
const struct feature_set *fset,
const struct crypto_state *cs, const struct crypto_state *cs,
const struct node_id *id, const struct node_id *id,
const struct wireaddr_internal *addr) const struct wireaddr_internal *addr)
@ -181,8 +182,8 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn,
* Finally, we agreed that bits below 13 could be put in both, but * Finally, we agreed that bits below 13 could be put in both, but
* from now on they'll all go in initfeatures. */ * from now on they'll all go in initfeatures. */
peer->msg = towire_init(NULL, peer->msg = towire_init(NULL,
get_offered_globalinitfeatures(tmpctx), fset->bits[GLOBAL_INIT_FEATURE],
get_offered_initfeatures(tmpctx), fset->bits[INIT_FEATURE],
tlvs); tlvs);
status_peer_io(LOG_IO_OUT, &peer->id, peer->msg); status_peer_io(LOG_IO_OUT, &peer->id, peer->msg);
peer->msg = cryptomsg_encrypt_msg(peer, &peer->cs, take(peer->msg)); peer->msg = cryptomsg_encrypt_msg(peer, &peer->cs, take(peer->msg));

1
connectd/peer_exchange_initmsg.h

@ -12,6 +12,7 @@ struct wireaddr_internal;
/* If successful, calls peer_connected() */ /* If successful, calls peer_connected() */
struct io_plan *peer_exchange_initmsg(struct io_conn *conn, struct io_plan *peer_exchange_initmsg(struct io_conn *conn,
struct daemon *daemon, struct daemon *daemon,
const struct feature_set *fset,
const struct crypto_state *cs, const struct crypto_state *cs,
const struct node_id *id, const struct node_id *id,
const struct wireaddr_internal *addr); const struct wireaddr_internal *addr);

3
connectd/test/run-initiator-success.c

@ -40,9 +40,6 @@ u8 *fromwire_tal_arrn(const tal_t *ctx UNNEEDED,
/* Generated stub for fromwire_u16 */ /* Generated stub for fromwire_u16 */
u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u16 called!\n"); abort(); } { fprintf(stderr, "fromwire_u16 called!\n"); abort(); }
/* Generated stub for notleak_ */
void *notleak_(const void *ptr UNNEEDED, bool plus_children UNNEEDED)
{ fprintf(stderr, "notleak_ called!\n"); abort(); }
/* Generated stub for towire_u16 */ /* Generated stub for towire_u16 */
void towire_u16(u8 **pptr UNNEEDED, u16 v UNNEEDED) void towire_u16(u8 **pptr UNNEEDED, u16 v UNNEEDED)
{ fprintf(stderr, "towire_u16 called!\n"); abort(); } { fprintf(stderr, "towire_u16 called!\n"); abort(); }

2
devtools/bolt11-cli.c

@ -93,7 +93,7 @@ int main(int argc, char *argv[])
errx(ERROR_USAGE, "Need argument\n%s", errx(ERROR_USAGE, "Need argument\n%s",
opt_usage(argv[0], NULL)); opt_usage(argv[0], NULL));
b11 = bolt11_decode(ctx, argv[2], description, &fail); b11 = bolt11_decode(ctx, argv[2], NULL, description, &fail);
if (!b11) if (!b11)
errx(ERROR_BAD_DECODE, "%s", fail); errx(ERROR_BAD_DECODE, "%s", fail);

3
gossipd/gossip_generation.c

@ -38,7 +38,8 @@ static u8 *create_node_announcement(const tal_t *ctx, struct daemon *daemon,
towire_wireaddr(&addresses, &daemon->announcable[i]); towire_wireaddr(&addresses, &daemon->announcable[i]);
announcement = announcement =
towire_node_announcement(ctx, sig, get_offered_nodefeatures(tmpctx), towire_node_announcement(ctx, sig,
daemon->fset->bits[NODE_ANNOUNCE_FEATURE],
timestamp, timestamp,
&daemon->id, daemon->rgb, daemon->alias, &daemon->id, daemon->rgb, daemon->alias,
addresses); addresses);

4
gossipd/gossipd.c

@ -831,11 +831,10 @@ static struct io_plan *gossip_init(struct io_conn *conn,
u32 *dev_gossip_time; u32 *dev_gossip_time;
bool dev_fast_gossip, dev_fast_gossip_prune; bool dev_fast_gossip, dev_fast_gossip_prune;
u32 timestamp; u32 timestamp;
struct feature_set *feature_set;
if (!fromwire_gossipctl_init(daemon, msg, if (!fromwire_gossipctl_init(daemon, msg,
&chainparams, &chainparams,
&feature_set, &daemon->fset,
&daemon->id, &daemon->id,
daemon->rgb, daemon->rgb,
daemon->alias, daemon->alias,
@ -846,7 +845,6 @@ static struct io_plan *gossip_init(struct io_conn *conn,
master_badmsg(WIRE_GOSSIPCTL_INIT, msg); master_badmsg(WIRE_GOSSIPCTL_INIT, msg);
} }
features_init(take(feature_set));
daemon->rstate = new_routing_state(daemon, daemon->rstate = new_routing_state(daemon,
&daemon->id, &daemon->id,
&daemon->peers, &daemon->peers,

3
gossipd/gossipd.h

@ -57,6 +57,9 @@ struct daemon {
/* What, if any, gossip we're seeker from peers. */ /* What, if any, gossip we're seeker from peers. */
struct seeker *seeker; struct seeker *seeker;
/* Features lightningd told us to set. */
struct feature_set *fset;
}; };
/* This represents each peer we're gossiping with */ /* This represents each peer we're gossiping with */

3
gossipd/test/run-extended-info.c

@ -78,9 +78,6 @@ void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UN
/* Generated stub for master_badmsg */ /* Generated stub for master_badmsg */
void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg) void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg)
{ fprintf(stderr, "master_badmsg called!\n"); abort(); } { fprintf(stderr, "master_badmsg called!\n"); abort(); }
/* Generated stub for notleak_ */
void *notleak_(const void *ptr UNNEEDED, bool plus_children UNNEEDED)
{ fprintf(stderr, "notleak_ called!\n"); abort(); }
/* Generated stub for peer_supplied_good_gossip */ /* Generated stub for peer_supplied_good_gossip */
void peer_supplied_good_gossip(struct peer *peer UNNEEDED, size_t amount UNNEEDED) void peer_supplied_good_gossip(struct peer *peer UNNEEDED, size_t amount UNNEEDED)
{ fprintf(stderr, "peer_supplied_good_gossip called!\n"); abort(); } { fprintf(stderr, "peer_supplied_good_gossip called!\n"); abort(); }

3
gossipd/test/run-next_block_range.c

@ -38,9 +38,6 @@ struct oneshot *new_reltimer_(struct timers *timers UNNEEDED,
struct timerel expire UNNEEDED, struct timerel expire UNNEEDED,
void (*cb)(void *) UNNEEDED, void *arg UNNEEDED) void (*cb)(void *) UNNEEDED, void *arg UNNEEDED)
{ fprintf(stderr, "new_reltimer_ called!\n"); abort(); } { fprintf(stderr, "new_reltimer_ called!\n"); abort(); }
/* Generated stub for notleak_ */
void *notleak_(const void *ptr UNNEEDED, bool plus_children UNNEEDED)
{ fprintf(stderr, "notleak_ called!\n"); abort(); }
/* Generated stub for query_channel_range */ /* Generated stub for query_channel_range */
bool query_channel_range(struct daemon *daemon UNNEEDED, bool query_channel_range(struct daemon *daemon UNNEEDED,
struct peer *peer UNNEEDED, struct peer *peer UNNEEDED,

6
lightningd/invoice.c

@ -1013,7 +1013,9 @@ static struct command_result *json_invoice(struct command *cmd,
info->b11->description_hash = NULL; info->b11->description_hash = NULL;
info->b11->payment_secret = tal_dup(info->b11, struct secret, info->b11->payment_secret = tal_dup(info->b11, struct secret,
&payment_secret); &payment_secret);
info->b11->features = get_offered_bolt11features(info->b11); info->b11->features = tal_dup_talarr(info->b11, u8,
cmd->ld->feature_set
->bits[BOLT11_FEATURE]);
#if DEVELOPER #if DEVELOPER
info->b11->routes = unpack_routes(info->b11, buffer, routes); info->b11->routes = unpack_routes(info->b11, buffer, routes);
@ -1319,7 +1321,7 @@ static struct command_result *json_decodepay(struct command *cmd,
NULL)) NULL))
return command_param_failed(); return command_param_failed();
b11 = bolt11_decode(cmd, str, desc, &fail); b11 = bolt11_decode(cmd, str, cmd->ld->feature_set, desc, &fail);
if (!b11) { if (!b11) {
return command_fail(cmd, LIGHTNINGD, "Invalid bolt11: %s", fail); return command_fail(cmd, LIGHTNINGD, "Invalid bolt11: %s", fail);

36
lightningd/lightningd.c

@ -703,6 +703,39 @@ static void setup_sig_handlers(void)
} }
} }
/*~ We actually keep more than one set of features, used in different
* contexts. common/features.c knows how each standard feature is
* presented, so we have it generate the set for each one at a time, and
* combine them.
*
* This is inefficient, but the primitives are useful for adding single
* features later, or adding them when supplied by plugins. */
static struct feature_set *default_features(const tal_t *ctx)
{
struct feature_set *ret = NULL;
static const u32 features[] = {
OPTIONAL_FEATURE(OPT_DATA_LOSS_PROTECT),
OPTIONAL_FEATURE(OPT_UPFRONT_SHUTDOWN_SCRIPT),
OPTIONAL_FEATURE(OPT_GOSSIP_QUERIES),
OPTIONAL_FEATURE(OPT_VAR_ONION),
OPTIONAL_FEATURE(OPT_PAYMENT_SECRET),
OPTIONAL_FEATURE(OPT_BASIC_MPP),
OPTIONAL_FEATURE(OPT_GOSSIP_QUERIES_EX),
OPTIONAL_FEATURE(OPT_STATIC_REMOTEKEY),
};
for (size_t i = 0; i < ARRAY_SIZE(features); i++) {
struct feature_set *f
= feature_set_for_feature(NULL, features[i]);
if (!ret)
ret = tal_steal(ctx, f);
else
feature_set_or(ret, take(f));
}
return ret;
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
struct lightningd *ld; struct lightningd *ld;
@ -751,6 +784,9 @@ int main(int argc, char *argv[])
if (!ld->daemon_dir) if (!ld->daemon_dir)
errx(1, "Could not find daemons"); errx(1, "Could not find daemons");
/* Set up the feature bits for what we support */
ld->feature_set = default_features(ld);
/*~ Handle early options; this moves us into --lightning-dir. /*~ Handle early options; this moves us into --lightning-dir.
* Plugins may add new options, which is why we are splitting * Plugins may add new options, which is why we are splitting
* between early args (including --plugin registration) and * between early args (including --plugin registration) and

2
lightningd/lightningd.h

@ -120,7 +120,7 @@ struct lightningd {
struct node_id id; struct node_id id;
/* Feature set we offer. */ /* Feature set we offer. */
const struct feature_set *feature_set; struct feature_set *feature_set;
/* My name is... my favorite color is... */ /* My name is... my favorite color is... */
u8 *alias; /* At least 32 bytes (zero-filled) */ u8 *alias; /* At least 32 bytes (zero-filled) */

6
lightningd/opening_control.c

@ -220,7 +220,8 @@ wallet_commit_channel(struct lightningd *ld,
*/ */
/* i.e. We set it now for the channel permanently. */ /* i.e. We set it now for the channel permanently. */
option_static_remotekey option_static_remotekey
= feature_negotiated(uc->peer->features, OPT_STATIC_REMOTEKEY); = feature_negotiated(ld->feature_set,
uc->peer->features, OPT_STATIC_REMOTEKEY);
channel = new_channel(uc->peer, uc->dbid, channel = new_channel(uc->peer, uc->dbid,
NULL, /* No shachain yet */ NULL, /* No shachain yet */
@ -1009,7 +1010,8 @@ void peer_start_openingd(struct peer *peer,
feerate_min(peer->ld, NULL), feerate_min(peer->ld, NULL),
feerate_max(peer->ld, NULL), feerate_max(peer->ld, NULL),
peer->features, peer->features,
feature_negotiated(peer->features, feature_negotiated(peer->ld->feature_set,
peer->features,
OPT_STATIC_REMOTEKEY), OPT_STATIC_REMOTEKEY),
send_msg, send_msg,
IFDEV(peer->ld->dev_force_tmp_channel_id, NULL), IFDEV(peer->ld->dev_force_tmp_channel_id, NULL),

25
lightningd/options.c

@ -692,7 +692,7 @@ static char *test_subdaemons_and_exit(struct lightningd *ld)
static char *list_features_and_exit(struct lightningd *ld) static char *list_features_and_exit(struct lightningd *ld)
{ {
const char **features = list_supported_features(ld); const char **features = list_supported_features(tmpctx, ld->feature_set);
for (size_t i = 0; i < tal_count(features); i++) for (size_t i = 0; i < tal_count(features); i++)
printf("%s\n", features[i]); printf("%s\n", features[i]);
exit(0); exit(0);
@ -1004,34 +1004,11 @@ void setup_color_and_alias(struct lightningd *ld)
} }
} }
static struct feature_set *setup_default_features(void)
{
static const u32 default_features[] = {
OPTIONAL_FEATURE(OPT_DATA_LOSS_PROTECT),
OPTIONAL_FEATURE(OPT_UPFRONT_SHUTDOWN_SCRIPT),
OPTIONAL_FEATURE(OPT_GOSSIP_QUERIES),
OPTIONAL_FEATURE(OPT_VAR_ONION),
OPTIONAL_FEATURE(OPT_PAYMENT_SECRET),
OPTIONAL_FEATURE(OPT_BASIC_MPP),
OPTIONAL_FEATURE(OPT_GOSSIP_QUERIES_EX),
OPTIONAL_FEATURE(OPT_STATIC_REMOTEKEY),
};
u8 *f = tal_arr(NULL, u8, 0);
for (size_t i = 0; i < ARRAY_SIZE(default_features); i++)
set_feature_bit(&f, default_features[i]);
return features_core_init(take(f));
}
void handle_early_opts(struct lightningd *ld, int argc, char *argv[]) void handle_early_opts(struct lightningd *ld, int argc, char *argv[])
{ {
/* Make ccan/opt use tal for allocations */ /* Make ccan/opt use tal for allocations */
setup_option_allocators(); setup_option_allocators();
/* Make sure options are populated. */
ld->feature_set = setup_default_features();
/*~ List features immediately, before doing anything interesting */ /*~ List features immediately, before doing anything interesting */
opt_register_early_noarg("--list-features-only", opt_register_early_noarg("--list-features-only",
list_features_and_exit, list_features_and_exit,

2
lightningd/pay.c

@ -1406,7 +1406,7 @@ static struct command_result *json_listsendpays(struct command *cmd,
struct bolt11 *b11; struct bolt11 *b11;
char *fail; char *fail;
b11 = bolt11_decode(cmd, b11str, NULL, &fail); b11 = bolt11_decode(cmd, b11str, cmd->ld->feature_set, NULL, &fail);
if (!b11) { if (!b11) {
return command_fail(cmd, JSONRPC2_INVALID_PARAMS, return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Invalid bolt11: %s", fail); "Invalid bolt11: %s", fail);

2
lightningd/plugin.c

@ -916,7 +916,7 @@ bool plugin_parse_getmanifest_response(const char *buffer,
return true; return true;
} }
if (!features_additional(fset)) { if (!feature_set_or(plugin->plugins->ld->feature_set, fset)) {
plugin_kill(plugin, plugin_kill(plugin,
"Custom featurebits already present"); "Custom featurebits already present");
return true; return true;

7
lightningd/test/run-find_my_abspath.c

@ -60,6 +60,13 @@ bool db_in_transaction(struct db *db UNNEEDED)
/* Generated stub for fatal */ /* Generated stub for fatal */
void fatal(const char *fmt UNNEEDED, ...) void fatal(const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "fatal called!\n"); abort(); } { fprintf(stderr, "fatal called!\n"); abort(); }
/* Generated stub for feature_set_for_feature */
struct feature_set *feature_set_for_feature(const tal_t *ctx UNNEEDED, int feature UNNEEDED)
{ fprintf(stderr, "feature_set_for_feature called!\n"); abort(); }
/* Generated stub for feature_set_or */
bool feature_set_or(struct feature_set *a UNNEEDED,
const struct feature_set *b TAKES UNNEEDED)
{ fprintf(stderr, "feature_set_or called!\n"); abort(); }
/* Generated stub for free_htlcs */ /* Generated stub for free_htlcs */
void free_htlcs(struct lightningd *ld UNNEEDED, const struct channel *channel UNNEEDED) void free_htlcs(struct lightningd *ld UNNEEDED, const struct channel *channel UNNEEDED)
{ fprintf(stderr, "free_htlcs called!\n"); abort(); } { fprintf(stderr, "free_htlcs called!\n"); abort(); }

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

@ -23,6 +23,7 @@ void bitcoind_getutxout_(struct bitcoind *bitcoind UNNEEDED,
{ fprintf(stderr, "bitcoind_getutxout_ called!\n"); abort(); } { fprintf(stderr, "bitcoind_getutxout_ called!\n"); abort(); }
/* Generated stub for bolt11_decode */ /* Generated stub for bolt11_decode */
struct bolt11 *bolt11_decode(const tal_t *ctx UNNEEDED, const char *str UNNEEDED, struct bolt11 *bolt11_decode(const tal_t *ctx UNNEEDED, const char *str UNNEEDED,
const struct feature_set *fset UNNEEDED,
const char *description UNNEEDED, char **fail UNNEEDED) const char *description UNNEEDED, char **fail UNNEEDED)
{ fprintf(stderr, "bolt11_decode called!\n"); abort(); } { fprintf(stderr, "bolt11_decode called!\n"); abort(); }
/* Generated stub for bolt11_encode_ */ /* Generated stub for bolt11_encode_ */
@ -137,9 +138,6 @@ u32 get_feerate(const struct fee_states *fee_states UNNEEDED,
enum side funder UNNEEDED, enum side funder UNNEEDED,
enum side side UNNEEDED) enum side side UNNEEDED)
{ fprintf(stderr, "get_feerate called!\n"); abort(); } { fprintf(stderr, "get_feerate called!\n"); abort(); }
/* Generated stub for get_offered_bolt11features */
u8 *get_offered_bolt11features(const tal_t *ctx UNNEEDED)
{ fprintf(stderr, "get_offered_bolt11features called!\n"); abort(); }
/* Generated stub for htlc_is_trimmed */ /* Generated stub for htlc_is_trimmed */
bool htlc_is_trimmed(enum side htlc_owner UNNEEDED, bool htlc_is_trimmed(enum side htlc_owner UNNEEDED,
struct amount_msat htlc_amount UNNEEDED, struct amount_msat htlc_amount UNNEEDED,

12
openingd/openingd.c

@ -113,6 +113,8 @@ struct state {
struct channel *channel; struct channel *channel;
bool option_static_remotekey; bool option_static_remotekey;
struct feature_set *fset;
}; };
static u8 *dev_upfront_shutdown_script(const tal_t *ctx) static u8 *dev_upfront_shutdown_script(const tal_t *ctx)
@ -563,7 +565,7 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags)
* `payment_basepoint`, or `delayed_payment_basepoint` are not * `payment_basepoint`, or `delayed_payment_basepoint` are not
* valid secp256k1 pubkeys in compressed format. * valid secp256k1 pubkeys in compressed format.
*/ */
if (feature_negotiated(state->features, if (feature_negotiated(state->fset, state->features,
OPT_UPFRONT_SHUTDOWN_SCRIPT)) { OPT_UPFRONT_SHUTDOWN_SCRIPT)) {
if (!fromwire_accept_channel_option_upfront_shutdown_script(state, if (!fromwire_accept_channel_option_upfront_shutdown_script(state,
msg, &id_in, msg, &id_in,
@ -644,6 +646,7 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags)
return towire_opening_funder_start_reply(state, return towire_opening_funder_start_reply(state,
funding_output_script, funding_output_script,
feature_negotiated( feature_negotiated(
state->fset,
state->features, state->features,
OPT_UPFRONT_SHUTDOWN_SCRIPT)); OPT_UPFRONT_SHUTDOWN_SCRIPT));
} }
@ -904,7 +907,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg)
* `payment_basepoint`, or `delayed_payment_basepoint` are not valid * `payment_basepoint`, or `delayed_payment_basepoint` are not valid
* secp256k1 pubkeys in compressed format. * secp256k1 pubkeys in compressed format.
*/ */
if (feature_negotiated(state->features, if (feature_negotiated(state->fset, state->features,
OPT_UPFRONT_SHUTDOWN_SCRIPT)) { OPT_UPFRONT_SHUTDOWN_SCRIPT)) {
if (!fromwire_open_channel_option_upfront_shutdown_script(state, if (!fromwire_open_channel_option_upfront_shutdown_script(state,
open_channel_msg, &chain_hash, open_channel_msg, &chain_hash,
@ -1481,7 +1484,6 @@ int main(int argc, char *argv[])
struct state *state = tal(NULL, struct state); struct state *state = tal(NULL, struct state);
struct secret *none; struct secret *none;
struct channel_id *force_tmp_channel_id; struct channel_id *force_tmp_channel_id;
struct feature_set *feature_set;
subdaemon_setup(argc, argv); subdaemon_setup(argc, argv);
@ -1493,7 +1495,7 @@ int main(int argc, char *argv[])
msg = wire_sync_read(tmpctx, REQ_FD); msg = wire_sync_read(tmpctx, REQ_FD);
if (!fromwire_opening_init(state, msg, if (!fromwire_opening_init(state, msg,
&chainparams, &chainparams,
&feature_set, &state->fset,
&state->localconf, &state->localconf,
&state->max_to_self_delay, &state->max_to_self_delay,
&state->min_effective_htlc_capacity, &state->min_effective_htlc_capacity,
@ -1509,8 +1511,6 @@ int main(int argc, char *argv[])
&dev_fast_gossip)) &dev_fast_gossip))
master_badmsg(WIRE_OPENING_INIT, msg); master_badmsg(WIRE_OPENING_INIT, msg);
features_init(take(feature_set));
#if DEVELOPER #if DEVELOPER
dev_force_tmp_channel_id = force_tmp_channel_id; dev_force_tmp_channel_id = force_tmp_channel_id;
#endif #endif

3
plugins/pay.c

@ -1283,7 +1283,8 @@ static struct command_result *json_pay(struct command *cmd,
NULL)) NULL))
return command_param_failed(); return command_param_failed();
b11 = bolt11_decode(cmd, b11str, NULL, &fail); /* FIXME: We need to know our features! */
b11 = bolt11_decode(cmd, b11str, NULL, NULL, &fail);
if (!b11) { if (!b11) {
return command_fail(cmd, JSONRPC2_INVALID_PARAMS, return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Invalid bolt11: %s", fail); "Invalid bolt11: %s", fail);

Loading…
Cancel
Save