Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
> [!IMPORTANT]
>
> 26.04 FREEZE March 11th: Non-bugfix PRs not ready by this date will wait for 26.06.
> 26.06 FREEZE April 30th: Non-bugfix PRs not ready by this date will wait for 26.09.
>
> RC1 is scheduled on _March 23rd_
> RC1 is scheduled on _May 14th_
>
> The final release is scheduled for April 15th.
> The final release is scheduled for June 1st.


## Checklist
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -409,8 +409,8 @@ jobs:
run: |
mkdir old-cln
cd old-cln
wget https://github.com/ElementsProject/lightning/releases/download/v25.12/clightning-v25.12-ubuntu-24.04-amd64.tar.xz
tar -xaf clightning-v25.12-ubuntu-24.04-amd64.tar.xz
wget https://github.com/ElementsProject/lightning/releases/download/v26.04/clightning-v26.04-ubuntu-24.04-amd64.tar.xz
tar -xaf clightning-v26.04-ubuntu-24.04-amd64.tar.xz

- name: Switch network
if: ${{ matrix.TEST_NETWORK == 'liquid-regtest' }}
Expand Down
11 changes: 7 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ VERSION ?= $(shell git describe --tags --always --dirty=-modded --abbrev=7 2>/de
$(info Building version $(VERSION))

# Next release.
CLN_NEXT_VERSION := v26.04
CLN_NEXT_VERSION := v26.06

# Previous release (for downgrade testing)
CLN_PREV_VERSION := v25.12
CLN_PREV_VERSION := v26.04

# --quiet / -s means quiet, dammit!
ifeq ($(findstring s,$(word 1, $(MAKEFLAGS))),s)
Expand All @@ -33,7 +33,7 @@ CCANDIR := ccan

# Where we keep the BOLT RFCs
BOLTDIR := ../bolts/
DEFAULT_BOLTVERSION := 68881992b97f20aca29edf7a4d673b8e6a70379a
DEFAULT_BOLTVERSION := 311119388a46dfa859da3d2eda0ca836cfc5f078
# Can be overridden on cmdline.
BOLTVERSION := $(DEFAULT_BOLTVERSION)

Expand Down Expand Up @@ -664,8 +664,11 @@ update-doc-examples:
check-doc-examples: update-doc-examples
git diff --exit-code HEAD

check-wire-format: extract-bolt-csv
git diff --exit-code HEAD

# This should NOT compile things!
check-source: check-makefile check-whitespace check-spelling check-python-flake8 check-includes check-shellcheck check-setup_locale check-tmpctx check-discouraged-functions check-amount-access check-bad-sprintf
check-source: check-makefile check-whitespace check-spelling check-python-flake8 check-includes check-shellcheck check-setup_locale check-tmpctx check-discouraged-functions check-amount-access check-bad-sprintf check-wire-format check-source-bolt

full-check: check check-source

Expand Down
6 changes: 3 additions & 3 deletions channeld/channeld.c
Original file line number Diff line number Diff line change
Expand Up @@ -6087,9 +6087,9 @@ static void peer_reconnect(struct peer *peer,
/* BOLT #2:
*
* - otherwise:
* - if `next_commitment_number` is not 1 greater than the
* commitment number of the last `commitment_signed` message the
* receiving node has sent:
* - if `next_commitment_number` is not equal to the commitment
* number of the next `commitment_signed` that the receiving
* node would send:
* - SHOULD send an `error` and fail the channel.
*/
} else if (next_commitment_number != peer->next_index[REMOTE])
Expand Down
20 changes: 17 additions & 3 deletions common/bech32_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,16 @@ static u8 get_u5_bit(const u5 *src, size_t bitoff)
return ((src[bitoff / 5] >> (4 - (bitoff % 5))) & 1);
}

void bech32_pull_bits(u8 **data, const u5 *src, size_t nbits)
bool bech32_pull_bits(u8 **data, const u5 *src, size_t nbits)
{
size_t i;
size_t data_len = tal_count(*data);
size_t pad = nbits % 8;

/* More than 4 padding bits means a superfluous u5 group was added. */
if (pad >= 5)
return false;

/* We discard trailing bits. */
for (i = 0; i + 8 <= nbits; i += 8) {
tal_resize(data, data_len+1);
(*data)[data_len] = 0;
Expand All @@ -46,6 +50,13 @@ void bech32_pull_bits(u8 **data, const u5 *src, size_t nbits)
}
data_len++;
}

/* Padding bits must all be zero. */
for (size_t b = 0; b < pad; b++) {
if (get_u5_bit(src, i + b))
return false;
}
return true;
}

/* Returns a char, tracks case. */
Expand Down Expand Up @@ -95,7 +106,10 @@ bool from_bech32_charset(const tal_t *ctx,
goto fail;

*data = tal_arr(ctx, u8, 0);
bech32_pull_bits(data, u5data, tal_bytelen(u5data) * 5);
if (!bech32_pull_bits(data, u5data, tal_bytelen(u5data) * 5)) {
tal_free(*data);
goto fail;
}
tal_free(u5data);
return true;

Expand Down
3 changes: 2 additions & 1 deletion common/bech32_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ void bech32_push_bits(u5 **data, const void *src, size_t nbits);

/**
* Push the bytes in src in 8 bit format onto the end of data.
* Returns false if padding bits are non-zero or exceed 4 bits.
*/
void bech32_pull_bits(u8 **data, const u5 *src, size_t nbits);
bool bech32_pull_bits(u8 **data, const u5 *src, size_t nbits);

/**
* Checksumless bech32 routines.
Expand Down
29 changes: 15 additions & 14 deletions common/bolt11.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ static const char *decode_p(struct bolt11 *b11,
/* BOLT #11:
*
* A reader...
* - MUST fail the payment if any mandatory field (`p`, `h`, `s`, `n`)
* - MUST fail the payment if any field with fixed `data_length` (`p`, `h`, `s`, `n`)
* does not have the correct length (52, 52, 52, 53).
*/
return pull_expected_length(b11, hu5, data, field_len, 52, 'p',
Expand Down Expand Up @@ -239,7 +239,7 @@ static const char *decode_h(struct bolt11 *b11,
/* BOLT #11:
*
* A reader...
* - MUST fail the payment if any mandatory field (`p`, `h`, `s`, `n`)
* - MUST fail the payment if any field with fixed `data_length` (`p`, `h`, `s`, `n`)
* does not have the correct length (52, 52, 52, 53). */
err = pull_expected_length(b11, hu5, data, field_len, 52, 'h',
have_h, &hash);
Expand Down Expand Up @@ -324,7 +324,7 @@ static const char *decode_n(struct bolt11 *b11,
/* BOLT #11:
*
* A reader...
* - MUST fail the payment if any mandatory field (`p`, `h`, `s`, `n`)
* - MUST fail the payment if any field with fixed `data_length` (`p`, `h`, `s`, `n`)
* does not have the correct length (52, 52, 52, 53). */
err = pull_expected_length(b11, hu5, data, field_len, 53, 'n', have_n,
&b11->receiver_id.k);
Expand Down Expand Up @@ -360,7 +360,7 @@ static const char *decode_s(struct bolt11 *b11,
/* BOLT #11:
*
* A reader...
* - MUST fail the payment if any mandatory field (`p`, `h`, `s`, `n`)
* - MUST fail the payment if any field with fixed `data_length` (`p`, `h`, `s`, `n`)
* does not have the correct length (52, 52, 52, 53). */
err = pull_expected_length(b11, hu5, data, field_len, 52, 's',
have_s, &secret);
Expand Down Expand Up @@ -876,7 +876,8 @@ struct bolt11 *bolt11_decode_nosig(const tal_t *ctx, const char *str,
*
* 1. `timestamp`: seconds-since-1970 (35 bits, big-endian)
* 1. zero or more tagged parts
* 1. `signature`: Bitcoin-style signature of above (520 bits)
* 1. `signature`: compact ECDSA/secp256k1 signature of the above
* (520 bits: 64-byte R||S + 1-byte recovery id)
*/
err = pull_uint(&hu5, &data, &data_len, &b11->timestamp, 35, false);
if (err)
Expand Down Expand Up @@ -999,13 +1000,12 @@ struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str,

/* BOLT #11:
*
* A writer...MUST set `signature` to a valid 512-bit
* secp256k1 signature of the SHA2 256-bit hash of the
* human-readable part, represented as UTF-8 bytes,
* concatenated with the data part (excluding the signature)
* with 0 bits appended to pad the data to the next byte
* boundary, with a trailing byte containing the recovery ID
* (0, 1, 2, or 3).
* A writer...MUST set `signature` to a valid
* compact ECDSA signature over secp256k1 of the SHA-256 hash of:
* the human-readable part (as UTF-8 bytes) concatenated with the data part
* (excluding the signature), with 0 bits appended to pad to a byte boundary.
* The signature is encoded as 64 bytes (R || S), followed by a trailing 1-byte
* recovery id in {0,1,2,3}.
*/
data_len = tal_count(sigdata);
err = pull_bits(NULL, &sigdata, &data_len, sig_and_recid, 520, false);
Expand Down Expand Up @@ -1036,7 +1036,7 @@ struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str,
* A reader:
* ...
* - if a valid `n` field is provided:
* - MUST use the `n` field to validate the signature instead of performing signature recovery.
* - MUST use the `n` field to validate the signature instead of performing public-key recovery.
*/
if (!have_n) {
struct pubkey k;
Expand Down Expand Up @@ -1319,7 +1319,8 @@ char *bolt11_encode_(const tal_t *ctx,
*
* 1. `timestamp`: seconds-since-1970 (35 bits, big-endian)
* 1. zero or more tagged parts
* 1. `signature`: Bitcoin-style signature of above (520 bits)
* 1. `signature`: compact ECDSA/secp256k1 signature of the above
* (520 bits: 64-byte R||S + 1-byte recovery id)
*/
push_varlen_uint(&data, b11->timestamp, 35);

Expand Down
21 changes: 18 additions & 3 deletions common/bolt12.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ bool bolt12_chains_match(const struct bitcoin_blkid *chains,
* - if the node does not accept bitcoin invoices:
* - MUST NOT respond to the offer
* - otherwise: (`offer_chains` is set):
* - if the node does not accept invoices for any of the `chains`:
* - if the node does not accept invoices for at least one of the `chains`:
* - MUST NOT respond to the offer
*/
if (!chains) {
Expand Down Expand Up @@ -62,6 +62,10 @@ static char *check_features_and_chain(const tal_t *ctx,
if (must_be_chain) {
if (!bolt12_chains_match(chains, num_chains, must_be_chain))
return tal_fmt(ctx, "wrong chain");
} else {
/* Chains is *empty*, that can never work. */
if (chains && tal_count(chains) == 0)
return tal_fmt(ctx, "offer_chains with zero entries");
}

if (our_features) {
Expand Down Expand Up @@ -223,7 +227,17 @@ struct tlv_offer *offer_decode(const tal_t *ctx,
}

/* BOLT #12:
*
*...
* - if `offer_amount` is set and is not greater than zero:
* - MUST NOT respond to the offer.
*/
if (offer->offer_amount && *offer->offer_amount == 0) {
*fail = tal_strdup(ctx, "Offer contains a zero amount");
return tal_free(offer);
}

/* BOLT #12:
*...
* - if `offer_currency` is set and `offer_amount` is not set:
* - MUST NOT respond to the offer.
*/
Expand All @@ -233,7 +247,7 @@ struct tlv_offer *offer_decode(const tal_t *ctx,
}

/* BOLT #12:
*
*...
* - if neither `offer_issuer_id` nor `offer_paths` are set:
* - MUST NOT respond to the offer.
*/
Expand All @@ -243,6 +257,7 @@ struct tlv_offer *offer_decode(const tal_t *ctx,
}

/* BOLT #12:
*...
* - if `num_hops` is 0 in any `blinded_path` in `offer_paths`:
* - MUST NOT respond to the offer.
*/
Expand Down
10 changes: 7 additions & 3 deletions common/features.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const char *feature_place_names[] = {
"bolt12_offer",
"bolt12_invreq",
"bolt12_invoice",
"channel_type",
};

static const struct feature_style feature_styles[] = {
Expand Down Expand Up @@ -81,7 +82,8 @@ static const struct feature_style feature_styles[] = {
{ OPT_ANCHORS_ZERO_FEE_HTLC_TX,
.copy_style = { [INIT_FEATURE] = FEATURE_REPRESENT,
[NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT,
[CHANNEL_FEATURE] = FEATURE_DONT_REPRESENT } },
[CHANNEL_FEATURE] = FEATURE_DONT_REPRESENT,
[CHANNEL_TYPE_FEATURE] = FEATURE_REPRESENT } },
{ OPT_DUAL_FUND,
.copy_style = { [INIT_FEATURE] = FEATURE_REPRESENT,
[NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT,
Expand All @@ -93,7 +95,8 @@ static const struct feature_style feature_styles[] = {
.copy_style = { [INIT_FEATURE] = FEATURE_REPRESENT,
[NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT,
[BOLT11_FEATURE] = FEATURE_DONT_REPRESENT,
[CHANNEL_FEATURE] = FEATURE_DONT_REPRESENT} },
[CHANNEL_FEATURE] = FEATURE_DONT_REPRESENT,
[CHANNEL_TYPE_FEATURE] = FEATURE_REPRESENT} },

/* Zeroconf is always signalled in `init`, but we still
* negotiate on a per-channel basis when calling `fundchannel`
Expand All @@ -106,7 +109,8 @@ static const struct feature_style feature_styles[] = {
[INIT_FEATURE] = FEATURE_REPRESENT,
[NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT,
[BOLT11_FEATURE] = FEATURE_DONT_REPRESENT,
[CHANNEL_FEATURE] = FEATURE_DONT_REPRESENT} },
[CHANNEL_FEATURE] = FEATURE_DONT_REPRESENT,
[CHANNEL_TYPE_FEATURE] = FEATURE_REPRESENT} },
{ OPT_ROUTE_BLINDING,
.copy_style = { [INIT_FEATURE] = FEATURE_REPRESENT,
[NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT,
Expand Down
13 changes: 7 additions & 6 deletions common/features.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ enum feature_place {
BOLT12_OFFER_FEATURE,
BOLT12_INVREQ_FEATURE,
BOLT12_INVOICE_FEATURE,
CHANNEL_TYPE_FEATURE,
};
#define NUM_FEATURE_PLACE (BOLT12_INVOICE_FEATURE+1)
#define NUM_FEATURE_PLACE (CHANNEL_TYPE_FEATURE+1)
extern const char *feature_place_names[NUM_FEATURE_PLACE];

/* The complete set of features for all contexts */
Expand Down Expand Up @@ -108,20 +109,20 @@ struct feature_set *feature_set_dup(const tal_t *ctx,
* | 8/9 | `var_onion_optin` |... ASSUMED ...
* | 10/11 | `gossip_queries_ex` |... IN ...
* | 12/13 | `option_static_remotekey` |... ASSUMED ...
* | 14/15 | `payment_secret` |... IN9 ...
* | 14/15 | `payment_secret` |... ASSUMED ...
* | 16/17 | `basic_mpp` |... IN9 ...
* | 18/19 | `option_support_large_channel` |... IN ...
* | 22/23 | `option_anchors` |... IN ...
* | 22/23 | `option_anchors` |... INT ...
* | 24/25 | `option_route_blinding` |...IN9 ...
* | 26/27 | `option_shutdown_anysegwit` |... IN ...
* | 28/29 | `option_dual_fund` |... IN ...
* | 34/35 | `option_quiesce` |... IN ...
* | 38/39 | `option_onion_messages` |... IN ...
* | 42/43 | `option_provide_storage` |... IN ...
* | 44/45 | `option_channel_type` |... IN ...
* | 46/47 | `option_scid_alias` | ... IN ...
* | 44/45 | `option_channel_type` |... ASSUMED ...
* | 46/47 | `option_scid_alias` | ... INT ...
* | 48/49 | `option_payment_metadata` |... 9 ...
* | 50/51 | `option_zeroconf` | ... IN ...
* | 50/51 | `option_zeroconf` | ... INT ...
* | 60/61 | `option_simple_close` |... IN ...
*/
/* BOLT-splice #9:
Expand Down
7 changes: 2 additions & 5 deletions common/sphinx.c
Original file line number Diff line number Diff line change
Expand Up @@ -768,9 +768,8 @@ struct onionreply *create_onionreply(const tal_t *ctx,

/* BOLT #4:
*
* The node generating the error message (_erring node_) builds a return
* packet consisting of
* the following fields:
* The node generating the error message builds a _return
* packet_ consisting of the following fields:
*
* 1. data:
* * [`32*byte`:`hmac`]
Expand Down Expand Up @@ -816,8 +815,6 @@ struct onionreply *wrap_onionreply(const tal_t *ctx,
* The erring node then generates a new key, using the key type `ammag`.
* This key is then used to generate a pseudo-random stream, which is
* in turn applied to the packet using `XOR`.
*
* The obfuscation step is repeated by every hop along the return path.
*/
subkey_from_hmac("ammag", shared_secret, &key);
result->contents = tal_dup_talarr(result, u8, reply->contents);
Expand Down
Loading
Loading