mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 15:14:23 +01:00
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>
This commit is contained in:
@@ -76,6 +76,9 @@ struct peer {
|
||||
/* Features peer supports. */
|
||||
u8 *features;
|
||||
|
||||
/* Features we support. */
|
||||
struct feature_set *fset;
|
||||
|
||||
/* Tolerable amounts for feerate (only relevant for fundee). */
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
first = LOCAL;
|
||||
@@ -2325,7 +2328,7 @@ static void peer_reconnect(struct peer *peer,
|
||||
bool dataloss_protect, check_extra_fields;
|
||||
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);
|
||||
|
||||
/* 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_bitcoin_sig;
|
||||
bool option_static_remotekey;
|
||||
struct feature_set *feature_set;
|
||||
#if !DEVELOPER
|
||||
bool dev_fail_process_onionpacket; /* Ignored */
|
||||
#endif
|
||||
@@ -3057,7 +3059,7 @@ static void init_channel(struct peer *peer)
|
||||
msg = wire_sync_read(tmpctx, MASTER_FD);
|
||||
if (!fromwire_channel_init(peer, msg,
|
||||
&chainparams,
|
||||
&feature_set,
|
||||
&peer->fset,
|
||||
&funding_txid, &funding_txout,
|
||||
&funding,
|
||||
&minimum_depth,
|
||||
@@ -3113,9 +3115,6 @@ static void init_channel(struct peer *peer)
|
||||
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 */
|
||||
per_peer_state_set_fds(peer->pps, 3, 4, 5);
|
||||
|
||||
|
||||
@@ -489,6 +489,7 @@ static void shift_bitmap_down(u8 *bitmap, size_t bits)
|
||||
* See [Feature Bits](#feature-bits).
|
||||
*/
|
||||
static char *decode_9(struct bolt11 *b11,
|
||||
const struct feature_set *fset,
|
||||
struct hash_u5 *hu5,
|
||||
u5 **data, size_t *data_len,
|
||||
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:
|
||||
* - MUST fail the payment.
|
||||
*/
|
||||
/* BOLT #11:
|
||||
* The field is big-endian. The least-significant bit is numbered 0,
|
||||
* which is _even_, and the next most significant bit is numbered 1,
|
||||
* which is _odd_. */
|
||||
badf = features_unsupported(b11->features);
|
||||
/* We skip this check for the cli tool, which sets fset to NULL */
|
||||
if (fset) {
|
||||
badf = features_unsupported(fset, b11->features, BOLT11_FEATURE);
|
||||
if (badf != -1)
|
||||
return tal_fmt(b11, "9: unknown feature bit %i", badf);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -545,6 +545,7 @@ struct bolt11 *new_bolt11(const tal_t *ctx,
|
||||
|
||||
/* Decodes and checks signature; returns NULL on error. */
|
||||
struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str,
|
||||
const struct feature_set *fset,
|
||||
const char *description, char **fail)
|
||||
{
|
||||
char *hrp, *amountstr, *prefix;
|
||||
@@ -739,7 +740,7 @@ struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str,
|
||||
data_length);
|
||||
break;
|
||||
case '9':
|
||||
problem = decode_9(b11, &hu5, &data, &data_len,
|
||||
problem = decode_9(b11, fset, &hu5, &data, &data_len,
|
||||
data_length);
|
||||
break;
|
||||
case 's':
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
/* We only have 10 bits for the field length, meaning < 640 bytes */
|
||||
#define BOLT11_FIELD_BYTE_LIMIT ((1 << 10) * 5 / 8)
|
||||
|
||||
struct feature_set;
|
||||
|
||||
struct bolt11_field {
|
||||
struct list_node list;
|
||||
|
||||
@@ -74,8 +76,11 @@ struct bolt11 {
|
||||
};
|
||||
|
||||
/* 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,
|
||||
const struct feature_set *fset,
|
||||
const char *description, char **fail);
|
||||
|
||||
/* Initialize an empty bolt11 struct with optional amount */
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
#include <common/utils.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 {
|
||||
/* Feature is not exposed (importantly, being 0, this is the default!). */
|
||||
FEATURE_DONT_REPRESENT,
|
||||
@@ -67,84 +63,53 @@ static enum feature_copy_style feature_copy_style(u32 f, enum feature_place p)
|
||||
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);
|
||||
const u8 *base = our_features->bits[INIT_FEATURE];
|
||||
struct feature_set *fs = tal(ctx, struct feature_set);
|
||||
|
||||
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:
|
||||
continue;
|
||||
case FEATURE_REPRESENT:
|
||||
set_feature_bit(&f, i);
|
||||
set_feature_bit(&fs->bits[i], feature);
|
||||
continue;
|
||||
case FEATURE_REPRESENT_AS_OPTIONAL:
|
||||
set_feature_bit(&f, OPTIONAL_FEATURE(i));
|
||||
set_feature_bit(&fs->bits[i], OPTIONAL_FEATURE(feature));
|
||||
continue;
|
||||
}
|
||||
abort();
|
||||
}
|
||||
return f;
|
||||
return fs;
|
||||
}
|
||||
|
||||
struct feature_set *features_core_init(const u8 *feature_bits)
|
||||
{
|
||||
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)
|
||||
bool feature_set_or(struct feature_set *a,
|
||||
const struct feature_set *b TAKES)
|
||||
{
|
||||
/* 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
|
||||
* to a compulsory one? */
|
||||
for (size_t b = 0; b < tal_bytelen(newfset->bits[i])*8; b++) {
|
||||
if (feature_is_set(newfset->bits[i], b)
|
||||
&& feature_is_set(our_features->bits[i], b))
|
||||
for (size_t j = 0; j < tal_bytelen(b->bits[i])*8; j++) {
|
||||
if (feature_is_set(b->bits[i], j)
|
||||
&& feature_offered(a->bits[i], j)) {
|
||||
if (taken(b))
|
||||
tal_free(b);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(newfset->bits); i++) {
|
||||
for (size_t b = 0; b < tal_bytelen(newfset->bits[i])*8; b++) {
|
||||
if (feature_is_set(newfset->bits[i], b))
|
||||
set_feature_bit(&our_features->bits[i], b);
|
||||
for (size_t i = 0; i < ARRAY_SIZE(a->bits); i++) {
|
||||
for (size_t j = 0; j < tal_bytelen(b->bits[i])*8; j++) {
|
||||
if (feature_is_set(b->bits[i], j))
|
||||
set_feature_bit(&a->bits[i], j);
|
||||
}
|
||||
}
|
||||
|
||||
if (taken(b))
|
||||
tal_free(b);
|
||||
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));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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
|
||||
* 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;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
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)
|
||||
&& 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.
|
||||
*/
|
||||
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;
|
||||
|
||||
@@ -272,7 +222,7 @@ static int all_supported_features(const u8 *bitmap)
|
||||
if (!test_bit(bitmap, bitnum/8, bitnum%8))
|
||||
continue;
|
||||
|
||||
if (feature_offered(our_features->bits[INIT_FEATURE], bitnum))
|
||||
if (feature_offered(ours->bits[p], bitnum))
|
||||
continue;
|
||||
|
||||
return bitnum;
|
||||
@@ -280,15 +230,16 @@ static int all_supported_features(const u8 *bitmap)
|
||||
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
|
||||
* 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)))
|
||||
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)
|
||||
@@ -313,12 +264,13 @@ static const char *feature_name(const tal_t *ctx, size_t f)
|
||||
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);
|
||||
|
||||
for (size_t i = 0; i < tal_bytelen(our_features->bits[INIT_FEATURE]) * 8; i++) {
|
||||
if (test_bit(our_features->bits[INIT_FEATURE], i / 8, i % 8))
|
||||
for (size_t i = 0; i < tal_bytelen(ours->bits[INIT_FEATURE]) * 8; i++) {
|
||||
if (test_bit(ours->bits[INIT_FEATURE], i / 8, i % 8))
|
||||
tal_arr_expand(&list, feature_name(list, i));
|
||||
}
|
||||
|
||||
|
||||
@@ -18,43 +18,38 @@ struct feature_set {
|
||||
u8 *bits[NUM_FEATURE_PLACE];
|
||||
};
|
||||
|
||||
/* Initialize core features (for lightningd). */
|
||||
struct feature_set *features_core_init(const u8 *features TAKES);
|
||||
|
||||
/* Initialize subdaemon features. */
|
||||
void features_init(struct feature_set *fset TAKES);
|
||||
|
||||
/* Free feature allocations */
|
||||
void features_cleanup(void);
|
||||
/* Create feature set for a known feature. */
|
||||
struct feature_set *feature_set_for_feature(const tal_t *ctx, int feature);
|
||||
|
||||
/* Marshalling a feature set */
|
||||
struct feature_set *fromwire_feature_set(const tal_t *ctx,
|
||||
const u8 **ptr, size_t *max);
|
||||
void towire_feature_set(u8 **pptr, const struct feature_set *fset);
|
||||
|
||||
/* Add features supplied by a plugin: returns false if we already have them */
|
||||
bool features_additional(const struct feature_set *feature_set);
|
||||
/* a |= b, or returns false if features already in a */
|
||||
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
|
||||
* unsupported (even) feature. */
|
||||
int features_unsupported(const u8 *features);
|
||||
|
||||
/* 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);
|
||||
int features_unsupported(const struct feature_set *ours, const u8 *theirs,
|
||||
enum feature_place p);
|
||||
|
||||
/* 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) */
|
||||
bool feature_offered(const u8 *features, size_t f);
|
||||
|
||||
/* 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. */
|
||||
const char **list_supported_features(const tal_t *ctx);
|
||||
/* Return a list of what (init) features we advertize. */
|
||||
const char **list_supported_features(const tal_t *ctx,
|
||||
const struct feature_set *ours);
|
||||
|
||||
/* Low-level helpers to deal with big-endian bitfields. */
|
||||
bool feature_is_set(const u8 *features, size_t bit);
|
||||
|
||||
@@ -64,7 +64,7 @@ static void test_b11(const char *b11str,
|
||||
char *reproduce;
|
||||
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)
|
||||
errx(1, "%s:%u:%s", __FILE__, __LINE__, fail);
|
||||
|
||||
@@ -145,11 +145,11 @@ int main(void)
|
||||
const char *badstr;
|
||||
struct bolt11_field *extra;
|
||||
char *fail;
|
||||
struct feature_set *fset;
|
||||
|
||||
wally_init(0);
|
||||
secp256k1_ctx = wally_get_secp_context();
|
||||
setup_tmpctx();
|
||||
features_core_init(NULL);
|
||||
|
||||
/* BOLT #11:
|
||||
*
|
||||
@@ -268,7 +268,7 @@ int main(void)
|
||||
|
||||
for (size_t i = 0; i <= strlen(badstr); i++) {
|
||||
if (bolt11_decode(tmpctx, tal_strndup(tmpctx, badstr, i),
|
||||
NULL, &fail))
|
||||
NULL, NULL, &fail))
|
||||
abort();
|
||||
assert(strstr(fail, "Bad bech32")
|
||||
|| strstr(fail, "Invoices must start with ln"));
|
||||
@@ -461,9 +461,23 @@ int main(void)
|
||||
set_feature_bit(&b11->features, 100);
|
||||
badstr = bolt11_encode(tmpctx, b11, false, test_sign, NULL);
|
||||
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"));
|
||||
|
||||
/* 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:
|
||||
*
|
||||
* > ### 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.
|
||||
* > lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrnt
|
||||
*/
|
||||
assert(!bolt11_decode(tmpctx, "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrnt", NULL, &fail));
|
||||
assert(!bolt11_decode(tmpctx, "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrnt", NULL, NULL, &fail));
|
||||
assert(streq(fail, "Bad bech32 string"));
|
||||
|
||||
/* BOLT-4e228a7fb4ea78af914d1ce82a63cbce8026279e #11:
|
||||
* > ### Malformed bech32 string (no 1)
|
||||
* > pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny
|
||||
*/
|
||||
assert(!bolt11_decode(tmpctx, "pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny", NULL, &fail));
|
||||
assert(!bolt11_decode(tmpctx, "pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny", NULL, NULL, &fail));
|
||||
assert(streq(fail, "Bad bech32 string"));
|
||||
|
||||
/* BOLT-4e228a7fb4ea78af914d1ce82a63cbce8026279e #11:
|
||||
* > ### Malformed bech32 string (mixed case)
|
||||
* > LNBC2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny
|
||||
*/
|
||||
assert(!bolt11_decode(tmpctx, "LNBC2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny", NULL, &fail));
|
||||
assert(!bolt11_decode(tmpctx, "LNBC2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny", NULL, NULL, &fail));
|
||||
assert(streq(fail, "Bad bech32 string"));
|
||||
|
||||
/* BOLT-4e228a7fb4ea78af914d1ce82a63cbce8026279e #11:
|
||||
* > ### Signature is not recoverable.
|
||||
* > lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaxtrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspk28uwq
|
||||
*/
|
||||
assert(!bolt11_decode(tmpctx, "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaxtrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspk28uwq", NULL, &fail));
|
||||
assert(!bolt11_decode(tmpctx, "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaxtrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspk28uwq", NULL, NULL, &fail));
|
||||
assert(streq(fail, "signature recovery failed"));
|
||||
|
||||
/* BOLT-4e228a7fb4ea78af914d1ce82a63cbce8026279e #11:
|
||||
* > ### String is too short.
|
||||
* > lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6na6hlh
|
||||
*/
|
||||
assert(!bolt11_decode(tmpctx, "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6na6hlh", NULL, &fail));
|
||||
assert(!bolt11_decode(tmpctx, "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6na6hlh", NULL, NULL, &fail));
|
||||
|
||||
/* BOLT-4e228a7fb4ea78af914d1ce82a63cbce8026279e #11:
|
||||
* > ### Invalid multiplier
|
||||
* > lnbc2500x1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpujr6jxr9gq9pv6g46y7d20jfkegkg4gljz2ea2a3m9lmvvr95tq2s0kvu70u3axgelz3kyvtp2ywwt0y8hkx2869zq5dll9nelr83zzqqpgl2zg
|
||||
*/
|
||||
assert(!bolt11_decode(tmpctx, "lnbc2500x1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpujr6jxr9gq9pv6g46y7d20jfkegkg4gljz2ea2a3m9lmvvr95tq2s0kvu70u3axgelz3kyvtp2ywwt0y8hkx2869zq5dll9nelr83zzqqpgl2zg", NULL, &fail));
|
||||
assert(!bolt11_decode(tmpctx, "lnbc2500x1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpujr6jxr9gq9pv6g46y7d20jfkegkg4gljz2ea2a3m9lmvvr95tq2s0kvu70u3axgelz3kyvtp2ywwt0y8hkx2869zq5dll9nelr83zzqqpgl2zg", NULL, NULL, &fail));
|
||||
assert(streq(fail, "Invalid amount postfix 'x'"));
|
||||
|
||||
/* BOLT- #11:
|
||||
* > ### Invalid sub-millisatoshi precision.
|
||||
* > lnbc2500000001p1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpu7hqtk93pkf7sw55rdv4k9z2vj050rxdr6za9ekfs3nlt5lr89jqpdmxsmlj9urqumg0h9wzpqecw7th56tdms40p2ny9q4ddvjsedzcplva53s
|
||||
*/
|
||||
assert(!bolt11_decode(tmpctx, "lnbc2500000001p1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpu7hqtk93pkf7sw55rdv4k9z2vj050rxdr6za9ekfs3nlt5lr89jqpdmxsmlj9urqumg0h9wzpqecw7th56tdms40p2ny9q4ddvjsedzcplva53s", NULL, &fail));
|
||||
assert(!bolt11_decode(tmpctx, "lnbc2500000001p1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpu7hqtk93pkf7sw55rdv4k9z2vj050rxdr6za9ekfs3nlt5lr89jqpdmxsmlj9urqumg0h9wzpqecw7th56tdms40p2ny9q4ddvjsedzcplva53s", NULL, NULL, &fail));
|
||||
assert(streq(fail, "Invalid sub-millisatoshi amount '2500000001p'"));
|
||||
|
||||
/* FIXME: Test the others! */
|
||||
wally_cleanup(0);
|
||||
tal_free(tmpctx);
|
||||
features_cleanup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -65,32 +65,70 @@ static void test_featurebits_or(void)
|
||||
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[] = {
|
||||
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]);
|
||||
features_core_init(take(f));
|
||||
/* We assume minimal sizing */
|
||||
for (size_t i = 0; i < ARRAY_SIZE(f1->bits); i++) {
|
||||
if (!memeq(f1->bits[i], tal_bytelen(f1->bits[i]),
|
||||
f2->bits[i], tal_bytelen(f2->bits[i])))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void test_feature_set_or(void)
|
||||
{
|
||||
struct feature_set *f1, *f2, *control;
|
||||
|
||||
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)
|
||||
{
|
||||
u8 *bits, *lf;
|
||||
u8 *bits;
|
||||
struct feature_set *fset;
|
||||
|
||||
setup_locale();
|
||||
wally_init(0);
|
||||
secp256k1_ctx = wally_get_secp_context();
|
||||
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);
|
||||
for (size_t i = 0; i < 100; i += 3)
|
||||
@@ -136,38 +174,37 @@ int main(void)
|
||||
|
||||
/* We always support no features. */
|
||||
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. */
|
||||
lf = get_offered_initfeatures(tmpctx);
|
||||
assert(features_unsupported(lf) == -1);
|
||||
assert(features_unsupported(fset, fset->bits[INIT_FEATURE], INIT_FEATURE) == -1);
|
||||
|
||||
/* We can add random odd features, no problem. */
|
||||
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);
|
||||
assert(features_unsupported(bits) == -1);
|
||||
assert(features_unsupported(fset, bits, INIT_FEATURE) == -1);
|
||||
}
|
||||
|
||||
/* We can't add random even features. */
|
||||
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);
|
||||
|
||||
/* Special case for missing compulsory feature */
|
||||
if (i == 2) {
|
||||
assert(features_unsupported(bits) == i);
|
||||
assert(features_unsupported(fset, bits, INIT_FEATURE) == i);
|
||||
} else {
|
||||
assert((features_unsupported(bits) == -1)
|
||||
== feature_offered(our_features->bits[INIT_FEATURE], i));
|
||||
assert((features_unsupported(fset, bits, INIT_FEATURE) == -1)
|
||||
== feature_offered(fset->bits[INIT_FEATURE], i));
|
||||
}
|
||||
}
|
||||
|
||||
test_featurebits_or();
|
||||
test_feature_set_or();
|
||||
|
||||
wally_cleanup(0);
|
||||
tal_free(tmpctx);
|
||||
take_cleanup();
|
||||
features_cleanup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -154,6 +154,9 @@ struct daemon {
|
||||
|
||||
/* Allow to define the default behavior of tor services calls*/
|
||||
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
|
||||
@@ -300,7 +303,7 @@ static bool get_gossipfds(struct daemon *daemon,
|
||||
/*~ The way features generally work is that both sides need to offer it;
|
||||
* we always offer `gossip_queries`, but this check is explicit. */
|
||||
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
|
||||
* 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:
|
||||
* - MUST fail the connection.
|
||||
*/
|
||||
unsup = features_unsupported(features);
|
||||
unsup = features_unsupported(daemon->fset, features, INIT_FEATURE);
|
||||
if (unsup != -1) {
|
||||
msg = towire_errorfmt(NULL, NULL, "Unsupported feature %u",
|
||||
unsup);
|
||||
@@ -490,7 +493,7 @@ static struct io_plan *handshake_in_success(struct io_conn *conn,
|
||||
struct node_id id;
|
||||
node_id_from_pubkey(&id, id_key);
|
||||
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
|
||||
@@ -550,7 +553,8 @@ static struct io_plan *handshake_out_success(struct io_conn *conn,
|
||||
node_id_from_pubkey(&id, key);
|
||||
connect->connstate = "Exchanging init messages";
|
||||
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)
|
||||
@@ -1201,14 +1205,13 @@ static struct io_plan *connect_init(struct io_conn *conn,
|
||||
struct wireaddr_internal *proposed_wireaddr;
|
||||
enum addr_listen_announce *proposed_listen_announce;
|
||||
struct wireaddr *announcable;
|
||||
struct feature_set *feature_set;
|
||||
char *tor_password;
|
||||
|
||||
/* Fields which require allocation are allocated off daemon */
|
||||
if (!fromwire_connectctl_init(
|
||||
daemon, msg,
|
||||
&chainparams,
|
||||
&feature_set,
|
||||
&daemon->fset,
|
||||
&daemon->id,
|
||||
&proposed_wireaddr,
|
||||
&proposed_listen_announce,
|
||||
@@ -1221,9 +1224,6 @@ static struct io_plan *connect_init(struct io_conn *conn,
|
||||
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))
|
||||
status_failed(STATUS_FAIL_INTERNAL_ERROR,
|
||||
"Invalid id for me %s",
|
||||
|
||||
@@ -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 daemon *daemon,
|
||||
const struct feature_set *fset,
|
||||
const struct crypto_state *cs,
|
||||
const struct node_id *id,
|
||||
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
|
||||
* from now on they'll all go in initfeatures. */
|
||||
peer->msg = towire_init(NULL,
|
||||
get_offered_globalinitfeatures(tmpctx),
|
||||
get_offered_initfeatures(tmpctx),
|
||||
fset->bits[GLOBAL_INIT_FEATURE],
|
||||
fset->bits[INIT_FEATURE],
|
||||
tlvs);
|
||||
status_peer_io(LOG_IO_OUT, &peer->id, peer->msg);
|
||||
peer->msg = cryptomsg_encrypt_msg(peer, &peer->cs, take(peer->msg));
|
||||
|
||||
@@ -12,6 +12,7 @@ struct wireaddr_internal;
|
||||
/* If successful, calls peer_connected() */
|
||||
struct io_plan *peer_exchange_initmsg(struct io_conn *conn,
|
||||
struct daemon *daemon,
|
||||
const struct feature_set *fset,
|
||||
const struct crypto_state *cs,
|
||||
const struct node_id *id,
|
||||
const struct wireaddr_internal *addr);
|
||||
|
||||
@@ -40,9 +40,6 @@ u8 *fromwire_tal_arrn(const tal_t *ctx UNNEEDED,
|
||||
/* Generated stub for fromwire_u16 */
|
||||
u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
{ 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 */
|
||||
void towire_u16(u8 **pptr UNNEEDED, u16 v UNNEEDED)
|
||||
{ fprintf(stderr, "towire_u16 called!\n"); abort(); }
|
||||
|
||||
@@ -93,7 +93,7 @@ int main(int argc, char *argv[])
|
||||
errx(ERROR_USAGE, "Need argument\n%s",
|
||||
opt_usage(argv[0], NULL));
|
||||
|
||||
b11 = bolt11_decode(ctx, argv[2], description, &fail);
|
||||
b11 = bolt11_decode(ctx, argv[2], NULL, description, &fail);
|
||||
if (!b11)
|
||||
errx(ERROR_BAD_DECODE, "%s", fail);
|
||||
|
||||
|
||||
@@ -38,7 +38,8 @@ static u8 *create_node_announcement(const tal_t *ctx, struct daemon *daemon,
|
||||
towire_wireaddr(&addresses, &daemon->announcable[i]);
|
||||
|
||||
announcement =
|
||||
towire_node_announcement(ctx, sig, get_offered_nodefeatures(tmpctx),
|
||||
towire_node_announcement(ctx, sig,
|
||||
daemon->fset->bits[NODE_ANNOUNCE_FEATURE],
|
||||
timestamp,
|
||||
&daemon->id, daemon->rgb, daemon->alias,
|
||||
addresses);
|
||||
|
||||
@@ -831,11 +831,10 @@ static struct io_plan *gossip_init(struct io_conn *conn,
|
||||
u32 *dev_gossip_time;
|
||||
bool dev_fast_gossip, dev_fast_gossip_prune;
|
||||
u32 timestamp;
|
||||
struct feature_set *feature_set;
|
||||
|
||||
if (!fromwire_gossipctl_init(daemon, msg,
|
||||
&chainparams,
|
||||
&feature_set,
|
||||
&daemon->fset,
|
||||
&daemon->id,
|
||||
daemon->rgb,
|
||||
daemon->alias,
|
||||
@@ -846,7 +845,6 @@ static struct io_plan *gossip_init(struct io_conn *conn,
|
||||
master_badmsg(WIRE_GOSSIPCTL_INIT, msg);
|
||||
}
|
||||
|
||||
features_init(take(feature_set));
|
||||
daemon->rstate = new_routing_state(daemon,
|
||||
&daemon->id,
|
||||
&daemon->peers,
|
||||
|
||||
@@ -57,6 +57,9 @@ struct daemon {
|
||||
|
||||
/* What, if any, gossip we're seeker from peers. */
|
||||
struct seeker *seeker;
|
||||
|
||||
/* Features lightningd told us to set. */
|
||||
struct feature_set *fset;
|
||||
};
|
||||
|
||||
/* This represents each peer we're gossiping with */
|
||||
|
||||
@@ -78,9 +78,6 @@ void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UN
|
||||
/* Generated stub for master_badmsg */
|
||||
void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg)
|
||||
{ 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 */
|
||||
void peer_supplied_good_gossip(struct peer *peer UNNEEDED, size_t amount UNNEEDED)
|
||||
{ fprintf(stderr, "peer_supplied_good_gossip called!\n"); abort(); }
|
||||
|
||||
@@ -38,9 +38,6 @@ struct oneshot *new_reltimer_(struct timers *timers UNNEEDED,
|
||||
struct timerel expire UNNEEDED,
|
||||
void (*cb)(void *) UNNEEDED, void *arg UNNEEDED)
|
||||
{ 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 */
|
||||
bool query_channel_range(struct daemon *daemon UNNEEDED,
|
||||
struct peer *peer UNNEEDED,
|
||||
|
||||
@@ -1013,7 +1013,9 @@ static struct command_result *json_invoice(struct command *cmd,
|
||||
info->b11->description_hash = NULL;
|
||||
info->b11->payment_secret = tal_dup(info->b11, struct 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
|
||||
info->b11->routes = unpack_routes(info->b11, buffer, routes);
|
||||
@@ -1319,7 +1321,7 @@ static struct command_result *json_decodepay(struct command *cmd,
|
||||
NULL))
|
||||
return command_param_failed();
|
||||
|
||||
b11 = bolt11_decode(cmd, str, desc, &fail);
|
||||
b11 = bolt11_decode(cmd, str, cmd->ld->feature_set, desc, &fail);
|
||||
|
||||
if (!b11) {
|
||||
return command_fail(cmd, LIGHTNINGD, "Invalid bolt11: %s", fail);
|
||||
|
||||
@@ -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[])
|
||||
{
|
||||
struct lightningd *ld;
|
||||
@@ -751,6 +784,9 @@ int main(int argc, char *argv[])
|
||||
if (!ld->daemon_dir)
|
||||
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.
|
||||
* Plugins may add new options, which is why we are splitting
|
||||
* between early args (including --plugin registration) and
|
||||
|
||||
@@ -120,7 +120,7 @@ struct lightningd {
|
||||
struct node_id id;
|
||||
|
||||
/* Feature set we offer. */
|
||||
const struct feature_set *feature_set;
|
||||
struct feature_set *feature_set;
|
||||
|
||||
/* My name is... my favorite color is... */
|
||||
u8 *alias; /* At least 32 bytes (zero-filled) */
|
||||
|
||||
@@ -220,7 +220,8 @@ wallet_commit_channel(struct lightningd *ld,
|
||||
*/
|
||||
/* i.e. We set it now for the channel permanently. */
|
||||
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,
|
||||
NULL, /* No shachain yet */
|
||||
@@ -1009,7 +1010,8 @@ void peer_start_openingd(struct peer *peer,
|
||||
feerate_min(peer->ld, NULL),
|
||||
feerate_max(peer->ld, NULL),
|
||||
peer->features,
|
||||
feature_negotiated(peer->features,
|
||||
feature_negotiated(peer->ld->feature_set,
|
||||
peer->features,
|
||||
OPT_STATIC_REMOTEKEY),
|
||||
send_msg,
|
||||
IFDEV(peer->ld->dev_force_tmp_channel_id, NULL),
|
||||
|
||||
@@ -692,7 +692,7 @@ static char *test_subdaemons_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++)
|
||||
printf("%s\n", features[i]);
|
||||
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[])
|
||||
{
|
||||
/* Make ccan/opt use tal for allocations */
|
||||
setup_option_allocators();
|
||||
|
||||
/* Make sure options are populated. */
|
||||
ld->feature_set = setup_default_features();
|
||||
|
||||
/*~ List features immediately, before doing anything interesting */
|
||||
opt_register_early_noarg("--list-features-only",
|
||||
list_features_and_exit,
|
||||
|
||||
@@ -1406,7 +1406,7 @@ static struct command_result *json_listsendpays(struct command *cmd,
|
||||
struct bolt11 *b11;
|
||||
char *fail;
|
||||
|
||||
b11 = bolt11_decode(cmd, b11str, NULL, &fail);
|
||||
b11 = bolt11_decode(cmd, b11str, cmd->ld->feature_set, NULL, &fail);
|
||||
if (!b11) {
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"Invalid bolt11: %s", fail);
|
||||
|
||||
@@ -916,7 +916,7 @@ bool plugin_parse_getmanifest_response(const char *buffer,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!features_additional(fset)) {
|
||||
if (!feature_set_or(plugin->plugins->ld->feature_set, fset)) {
|
||||
plugin_kill(plugin,
|
||||
"Custom featurebits already present");
|
||||
return true;
|
||||
|
||||
@@ -60,6 +60,13 @@ bool db_in_transaction(struct db *db UNNEEDED)
|
||||
/* Generated stub for fatal */
|
||||
void fatal(const char *fmt UNNEEDED, ...)
|
||||
{ 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 */
|
||||
void free_htlcs(struct lightningd *ld UNNEEDED, const struct channel *channel UNNEEDED)
|
||||
{ fprintf(stderr, "free_htlcs called!\n"); abort(); }
|
||||
|
||||
@@ -23,6 +23,7 @@ void bitcoind_getutxout_(struct bitcoind *bitcoind UNNEEDED,
|
||||
{ fprintf(stderr, "bitcoind_getutxout_ called!\n"); abort(); }
|
||||
/* Generated stub for bolt11_decode */
|
||||
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)
|
||||
{ fprintf(stderr, "bolt11_decode called!\n"); abort(); }
|
||||
/* 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 side UNNEEDED)
|
||||
{ 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 */
|
||||
bool htlc_is_trimmed(enum side htlc_owner UNNEEDED,
|
||||
struct amount_msat htlc_amount UNNEEDED,
|
||||
|
||||
@@ -113,6 +113,8 @@ struct state {
|
||||
struct channel *channel;
|
||||
|
||||
bool option_static_remotekey;
|
||||
|
||||
struct feature_set *fset;
|
||||
};
|
||||
|
||||
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
|
||||
* valid secp256k1 pubkeys in compressed format.
|
||||
*/
|
||||
if (feature_negotiated(state->features,
|
||||
if (feature_negotiated(state->fset, state->features,
|
||||
OPT_UPFRONT_SHUTDOWN_SCRIPT)) {
|
||||
if (!fromwire_accept_channel_option_upfront_shutdown_script(state,
|
||||
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,
|
||||
funding_output_script,
|
||||
feature_negotiated(
|
||||
state->fset,
|
||||
state->features,
|
||||
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
|
||||
* secp256k1 pubkeys in compressed format.
|
||||
*/
|
||||
if (feature_negotiated(state->features,
|
||||
if (feature_negotiated(state->fset, state->features,
|
||||
OPT_UPFRONT_SHUTDOWN_SCRIPT)) {
|
||||
if (!fromwire_open_channel_option_upfront_shutdown_script(state,
|
||||
open_channel_msg, &chain_hash,
|
||||
@@ -1481,7 +1484,6 @@ int main(int argc, char *argv[])
|
||||
struct state *state = tal(NULL, struct state);
|
||||
struct secret *none;
|
||||
struct channel_id *force_tmp_channel_id;
|
||||
struct feature_set *feature_set;
|
||||
|
||||
subdaemon_setup(argc, argv);
|
||||
|
||||
@@ -1493,7 +1495,7 @@ int main(int argc, char *argv[])
|
||||
msg = wire_sync_read(tmpctx, REQ_FD);
|
||||
if (!fromwire_opening_init(state, msg,
|
||||
&chainparams,
|
||||
&feature_set,
|
||||
&state->fset,
|
||||
&state->localconf,
|
||||
&state->max_to_self_delay,
|
||||
&state->min_effective_htlc_capacity,
|
||||
@@ -1509,8 +1511,6 @@ int main(int argc, char *argv[])
|
||||
&dev_fast_gossip))
|
||||
master_badmsg(WIRE_OPENING_INIT, msg);
|
||||
|
||||
features_init(take(feature_set));
|
||||
|
||||
#if DEVELOPER
|
||||
dev_force_tmp_channel_id = force_tmp_channel_id;
|
||||
#endif
|
||||
|
||||
@@ -1283,7 +1283,8 @@ static struct command_result *json_pay(struct command *cmd,
|
||||
NULL))
|
||||
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) {
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"Invalid bolt11: %s", fail);
|
||||
|
||||
Reference in New Issue
Block a user