diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index df5969859648..dac258bf2bd9 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -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 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index eefdca61522f..7ab7618ff538 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -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' }} diff --git a/Makefile b/Makefile index 682e3f368bc8..61c86087a645 100644 --- a/Makefile +++ b/Makefile @@ -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) @@ -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) @@ -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 diff --git a/channeld/channeld.c b/channeld/channeld.c index 6fa715803057..11d8fdeea572 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -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]) diff --git a/common/bech32_util.c b/common/bech32_util.c index b72777e7dc06..3722a19cb200 100644 --- a/common/bech32_util.c +++ b/common/bech32_util.c @@ -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; @@ -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. */ @@ -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; diff --git a/common/bech32_util.h b/common/bech32_util.h index f2857bde4935..fbd71d0470bf 100644 --- a/common/bech32_util.h +++ b/common/bech32_util.h @@ -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. diff --git a/common/bolt11.c b/common/bolt11.c index bd15e3af1320..26263dd028c0 100644 --- a/common/bolt11.c +++ b/common/bolt11.c @@ -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', @@ -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); @@ -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); @@ -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); @@ -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) @@ -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); @@ -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; @@ -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); diff --git a/common/bolt12.c b/common/bolt12.c index 4621e62f6960..1f2ccf1b659d 100644 --- a/common/bolt12.c +++ b/common/bolt12.c @@ -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) { @@ -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) { @@ -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. */ @@ -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. */ @@ -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. */ diff --git a/common/features.c b/common/features.c index 0de221dad443..7b6ed6cb5458 100644 --- a/common/features.c +++ b/common/features.c @@ -29,6 +29,7 @@ const char *feature_place_names[] = { "bolt12_offer", "bolt12_invreq", "bolt12_invoice", + "channel_type", }; static const struct feature_style feature_styles[] = { @@ -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, @@ -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` @@ -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, diff --git a/common/features.h b/common/features.h index 9a9783d92924..2861573647ea 100644 --- a/common/features.h +++ b/common/features.h @@ -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 */ @@ -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: diff --git a/common/sphinx.c b/common/sphinx.c index 6761c79f945c..7adea81627d5 100644 --- a/common/sphinx.c +++ b/common/sphinx.c @@ -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`] @@ -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); diff --git a/common/test/run-bolt11.c b/common/test/run-bolt11.c index b36ae7966f2a..33b228bc7df8 100644 --- a/common/test/run-bolt11.c +++ b/common/test/run-bolt11.c @@ -3,6 +3,7 @@ #include "../bech32.c" #include "../bech32_util.c" #include "../bolt11.c" +#include "../json_param.c" #include "../features.c" #include "../node_id.c" #include "../hash_u5.c" @@ -13,6 +14,137 @@ #include /* AUTOGENERATED MOCKS START */ +/* Generated stub for command_check_done */ +struct command_result *command_check_done(struct command *cmd) + +{ fprintf(stderr, "command_check_done called!\n"); abort(); } +/* Generated stub for command_check_only */ +bool command_check_only(const struct command *cmd UNNEEDED) +{ fprintf(stderr, "command_check_only called!\n"); abort(); } +/* Generated stub for command_deprecated_in_ok */ +bool command_deprecated_in_ok(struct command *cmd UNNEEDED, + const char *param UNNEEDED, + const char *depr_start UNNEEDED, + const char *depr_end UNNEEDED) +{ fprintf(stderr, "command_deprecated_in_ok called!\n"); abort(); } +/* Generated stub for command_dev_apis */ +bool command_dev_apis(const struct command *cmd UNNEEDED) +{ fprintf(stderr, "command_dev_apis called!\n"); abort(); } +/* Generated stub for command_fail */ +struct command_result *command_fail(struct command *cmd UNNEEDED, enum jsonrpc_errcode code UNNEEDED, + const char *fmt UNNEEDED, ...) + +{ fprintf(stderr, "command_fail called!\n"); abort(); } +/* Generated stub for command_fail_badparam */ +struct command_result *command_fail_badparam(struct command *cmd UNNEEDED, + const char *paramname UNNEEDED, + const char *buffer UNNEEDED, + const jsmntok_t *tok UNNEEDED, + const char *msg UNNEEDED) +{ fprintf(stderr, "command_fail_badparam called!\n"); abort(); } +/* Generated stub for command_set_usage */ +void command_set_usage(struct command *cmd UNNEEDED, const char *usage UNNEEDED) +{ fprintf(stderr, "command_set_usage called!\n"); abort(); } +/* Generated stub for command_usage_only */ +bool command_usage_only(const struct command *cmd UNNEEDED) +{ fprintf(stderr, "command_usage_only called!\n"); abort(); } +/* Generated stub for json_get_membern */ +const jsmntok_t *json_get_membern(const char *buffer UNNEEDED, + const jsmntok_t tok[] UNNEEDED, + const char *label UNNEEDED, size_t len UNNEEDED) +{ fprintf(stderr, "json_get_membern called!\n"); abort(); } +/* Generated stub for json_next */ +const jsmntok_t *json_next(const jsmntok_t *tok UNNEEDED) +{ fprintf(stderr, "json_next called!\n"); abort(); } +/* Generated stub for json_scan */ +const char *json_scan(const tal_t *ctx UNNEEDED, + const char *buffer UNNEEDED, + const jsmntok_t *tok UNNEEDED, + const char *guide UNNEEDED, + ...) +{ fprintf(stderr, "json_scan called!\n"); abort(); } +/* Generated stub for json_strdup */ +char *json_strdup(const tal_t *ctx UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED) +{ fprintf(stderr, "json_strdup called!\n"); abort(); } +/* Generated stub for json_to_bool */ +bool json_to_bool(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, bool *b UNNEEDED) +{ fprintf(stderr, "json_to_bool called!\n"); abort(); } +/* Generated stub for json_to_channel_id */ +bool json_to_channel_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + struct channel_id *cid UNNEEDED) +{ fprintf(stderr, "json_to_channel_id called!\n"); abort(); } +/* Generated stub for json_to_millionths */ +bool json_to_millionths(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + u64 *millionths UNNEEDED) +{ fprintf(stderr, "json_to_millionths called!\n"); abort(); } +/* Generated stub for json_to_msat */ +bool json_to_msat(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + struct amount_msat *msat UNNEEDED) +{ fprintf(stderr, "json_to_msat called!\n"); abort(); } +/* Generated stub for json_to_node_id */ +bool json_to_node_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + struct node_id *id UNNEEDED) +{ fprintf(stderr, "json_to_node_id called!\n"); abort(); } +/* Generated stub for json_to_number */ +bool json_to_number(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + unsigned int *num UNNEEDED) +{ fprintf(stderr, "json_to_number called!\n"); abort(); } +/* Generated stub for json_to_outpoint */ +bool json_to_outpoint(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + struct bitcoin_outpoint *op UNNEEDED) +{ fprintf(stderr, "json_to_outpoint called!\n"); abort(); } +/* Generated stub for json_to_pubkey */ +bool json_to_pubkey(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + struct pubkey *pubkey UNNEEDED) +{ fprintf(stderr, "json_to_pubkey called!\n"); abort(); } +/* Generated stub for json_to_s64 */ +bool json_to_s64(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, s64 *num UNNEEDED) +{ fprintf(stderr, "json_to_s64 called!\n"); abort(); } +/* Generated stub for json_to_short_channel_id */ +bool json_to_short_channel_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + struct short_channel_id *scid UNNEEDED) +{ fprintf(stderr, "json_to_short_channel_id called!\n"); abort(); } +/* Generated stub for json_to_short_channel_id_dir */ +bool json_to_short_channel_id_dir(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + struct short_channel_id_dir *scidd UNNEEDED) +{ fprintf(stderr, "json_to_short_channel_id_dir called!\n"); abort(); } +/* Generated stub for json_to_txid */ +bool json_to_txid(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + struct bitcoin_txid *txid UNNEEDED) +{ fprintf(stderr, "json_to_txid called!\n"); abort(); } +/* Generated stub for json_to_u16 */ +bool json_to_u16(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + uint16_t *num UNNEEDED) +{ fprintf(stderr, "json_to_u16 called!\n"); abort(); } +/* Generated stub for json_to_u32 */ +bool json_to_u32(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, u32 *num UNNEEDED) +{ fprintf(stderr, "json_to_u32 called!\n"); abort(); } +/* Generated stub for json_to_u64 */ +bool json_to_u64(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, u64 *num UNNEEDED) +{ fprintf(stderr, "json_to_u64 called!\n"); abort(); } +/* Generated stub for json_tok_bin_from_hex */ +u8 *json_tok_bin_from_hex(const tal_t *ctx UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED) +{ fprintf(stderr, "json_tok_bin_from_hex called!\n"); abort(); } +/* Generated stub for json_tok_full */ +const char *json_tok_full(const char *buffer UNNEEDED, const jsmntok_t *t UNNEEDED) +{ fprintf(stderr, "json_tok_full called!\n"); abort(); } +/* Generated stub for json_tok_full_len */ +int json_tok_full_len(const jsmntok_t *t UNNEEDED) +{ fprintf(stderr, "json_tok_full_len called!\n"); abort(); } +/* Generated stub for json_tok_is_null */ +bool json_tok_is_null(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED) +{ fprintf(stderr, "json_tok_is_null called!\n"); abort(); } +/* Generated stub for json_tok_is_num */ +bool json_tok_is_num(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED) +{ fprintf(stderr, "json_tok_is_num called!\n"); abort(); } +/* Generated stub for json_tok_strneq */ +bool json_tok_strneq(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, + const char *str UNNEEDED, size_t len UNNEEDED) +{ fprintf(stderr, "json_tok_strneq called!\n"); abort(); } +/* Generated stub for lease_rates_fromhex */ +struct lease_rates *lease_rates_fromhex(const tal_t *ctx UNNEEDED, + const char *hexdata UNNEEDED, size_t len UNNEEDED) +{ fprintf(stderr, "lease_rates_fromhex called!\n"); abort(); } /* Generated stub for siphash_seed */ const struct siphash_seed *siphash_seed(void) { fprintf(stderr, "siphash_seed called!\n"); abort(); } @@ -127,6 +259,27 @@ static void test_b11(const char *b11str, assert(strlen(reproduce) == strlen(b11str)); } +static const u8 **fallbacks(const tal_t *ctx, + const struct chainparams *chainparams, + const char *addr) +{ + jsmntok_t tok; + const u8 **addrs = tal_arr(ctx, const u8 *, 1); + + tok.type = JSMN_STRING; + tok.start = 0; + tok.end = strlen(addr); + tok.size = tok.end; + + /* Reuse what we use in json_invoice for fallbacks! */ + assert(json_to_address_scriptpubkey(ctx, + chainparams, + addr, &tok, + &addrs[0]) + == ADDRESS_PARSE_SUCCESS); + return addrs; +} + int main(int argc, char *argv[]) { struct bolt11 *b11; @@ -287,6 +440,55 @@ int main(int argc, char *argv[]) test_b11("lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qrsgq7ea976txfraylvgzuxs8kgcw23ezlrszfnh8r6qtfpr6cxga50aj6txm9rxrydzd06dfeawfk6swupvz4erwnyutnjq7x39ymw6j38gp7ynn44", b11, "One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon"); dev_bolt11_omit_c_value = false; + /* BOLT #11: + * > ### On mainnet, with fallback (P2TR) address bc1pptdvg0d2nj99568qn6ssdy4cygnwuxgw2ukmnwgwz7jpqjz2kszse2s3lm + * > + * lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfp4pptdvg0d2nj99568qn6ssdy4cygnwuxgw2ukmnwgwz7jpqjz2kszs9qrsgqy606dznq28exnydt2r4c29y56xjtn3sk4mhgjtl4pg2y4ar3249rq4ajlmj9jy8zvlzw7cr8mggqzm842xfr0v72rswzq9xvr4hknfsqwmn6xd + * + * * `lnbc`: prefix, Lightning on Bitcoin mainnet + * * `20m`: amount (20 milli-bitcoin) + * * `1`: Bech32 separator + * * `pvjluez`: timestamp (1496314658) + * * `s`: payment secret... + * * `p`: payment hash... + * * `h`: tagged field: hash of description... + * * `f`: tagged field: fallback address + * * `p4`: `data_length` (`p` = 1, `4` = 21; 1 * 32 + 21 == 53) + * * `p`: 1, so witness version 1 + * * `ptdvg0d2nj99568qn6ssdy4cygnwuxgw2ukmnwgwz7jpqjz2kszs`: 260 bits = P2TR. + * * `9`: features... + * * `y606dznq28exnydt2r4c29y56xjtn3sk4mhgjtl4pg2y4ar3249rq4ajlmj9jy8zvlzw7cr8mggqzm842xfr0v72rswzq9xvr4hknfsq`: signature + * * `wmn6xd`: Bech32 checksum + * * Signature breakdown: + * * `269fa68a6051f26991ab50eb851494d1a4b9c616aeee892ff50a144af471554a3057b2fee45910e267c4ef6067da10016cf5519237b3ca1c1c2014cc1d6f69a6` hex of signature data (32-byte r, 32-byte s) + * * `0` (int) recovery flag contained in `signature` + * * `6c6e626332306d0b25fe64500d04444444444444444444444444444444444444444444444444444444444444444021a000081018202830384048000810182028303840480008101820283038404808105c343925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c10486a10adac43daa9c8a5a68e09ea10692b82226ee190e572db9b90e17a410484ab4050280704000` hex of data for signing (prefix + data after separator up to the start of the signature) + * * `116fdb0f18352c886deb263f6466eb40e5e6518b80231a1f9df86088bfa48043` hex of SHA256 of the preimage + * */ + msatoshi = AMOUNT_MSAT(20 * (1000ULL * 100000000) / 1000); + b11 = new_bolt11(tmpctx, &msatoshi); + b11->chain = chainparams_for_network("bitcoin"); + b11->timestamp = 1496314658; + b11->payment_secret = tal(b11, struct secret); + memset(b11->payment_secret, 0x11, sizeof(*b11->payment_secret)); + if (!hex_decode("0001020304050607080900010203040506070809000102030405060708090102", + strlen("0001020304050607080900010203040506070809000102030405060708090102"), + &b11->payment_hash, sizeof(b11->payment_hash))) + abort(); + b11->receiver_id = node; + b11->description_hash = tal(b11, struct sha256); + if (!hex_decode("3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1", + strlen("3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1"), + b11->description_hash, sizeof(*b11->description_hash))) + abort(); + set_feature_bit(&b11->features, 8); + set_feature_bit(&b11->features, 14); + b11->fallbacks = fallbacks(b11, b11->chain, "bc1pptdvg0d2nj99568qn6ssdy4cygnwuxgw2ukmnwgwz7jpqjz2kszse2s3lm"); + + dev_bolt11_omit_c_value = true; + test_b11("lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfp4pptdvg0d2nj99568qn6ssdy4cygnwuxgw2ukmnwgwz7jpqjz2kszs9qrsgqy606dznq28exnydt2r4c29y56xjtn3sk4mhgjtl4pg2y4ar3249rq4ajlmj9jy8zvlzw7cr8mggqzm842xfr0v72rswzq9xvr4hknfsqwmn6xd", b11, "One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon"); + dev_bolt11_omit_c_value = false; + /* Malformed bolt11 strings (no '1'). */ badstr = "lnbc20mpvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqscc6gd6ql3jrc5yzme8v4ntcewwz5cnw92tz0pc8qcuufvq7khhr8wpald05e92xw006sq94mg8v2ndf4sefvf9sygkshp5zfem29trqq2yxxz7"; diff --git a/common/test/run-bolt12-encode-test.c b/common/test/run-bolt12-encode-test.c index 911ce003c53b..9391b1a38a08 100644 --- a/common/test/run-bolt12-encode-test.c +++ b/common/test/run-bolt12-encode-test.c @@ -429,6 +429,8 @@ int main(int argc, char *argv[]) /* BOLT #12: * - if `offer_amount` is set and `offer_description` is not set: * - MUST NOT respond to the offer. + * - if `offer_amount` is set and is not greater than zero: + * - MUST NOT respond to the offer. * - if `offer_currency` is set and `offer_amount` is not set: * - MUST NOT respond to the offer. * - if neither `offer_issuer_id` nor `offer_paths` are set: @@ -438,8 +440,18 @@ int main(int argc, char *argv[]) print_invalid_offer(offer, "Missing offer_description and offer_amount"); offer->offer_description = tal_utf8(tmpctx, "Test vectors"); + offer->offer_amount = tal(offer, u64); + *offer->offer_amount = 0; + print_invalid_offer(offer, "Zero offer_amount"); + offer->offer_amount = tal_free(offer->offer_amount); + offer->offer_currency = tal_utf8(offer, "USD"); print_invalid_offer(offer, "Missing offer_amount with offer_currency"); + + offer->offer_amount = tal(offer, u64); + *offer->offer_amount = 0; + print_invalid_offer(offer, "Zero offer_amount with currency"); + offer->offer_amount = tal_free(offer->offer_amount); offer->offer_currency = NULL; offer->offer_issuer_id = NULL; @@ -448,6 +460,11 @@ int main(int argc, char *argv[]) offer->offer_paths = paths; offer->offer_paths[1]->path = NULL; print_invalid_offer(offer, "Second offer_path is empty"); + offer->offer_paths = NULL; + + offer->offer_chains = tal_arr(offer, struct bitcoin_blkid, 0); + print_invalid_offer(offer, "offer_chains with zero entries"); + offer->offer_chains = NULL; printf("]\n"); common_shutdown(); diff --git a/common/test/run-bolt12-format-string-test.c b/common/test/run-bolt12-format-string-test.c index d517a60cf11d..10f6748b2ddd 100644 --- a/common/test/run-bolt12-format-string-test.c +++ b/common/test/run-bolt12-format-string-test.c @@ -128,6 +128,7 @@ int main(int argc, char *argv[]) * - SHOULD omit `offer_chains`, implying that bitcoin is only chain. * - if a specific minimum `offer_amount` is required for successful payment: * - MUST set `offer_amount` to the amount expected (per item). + * - MUST set `offer_amount` greater than zero. * - if the currency for `offer_amount` is that of all entries in `chains`: * - MUST specify `offer_amount` in multiples of the minimum lightning-payable unit * (e.g. milli-satoshis for bitcoin). diff --git a/contrib/pyln-proto/pyln/proto/invoice.py b/contrib/pyln-proto/pyln/proto/invoice.py index 27591cb040e0..9a53f871f672 100755 --- a/contrib/pyln-proto/pyln/proto/invoice.py +++ b/contrib/pyln-proto/pyln/proto/invoice.py @@ -329,7 +329,8 @@ def decode(cls, b): # BOLT #11: # A reader: # - MUST skip over `f` fields that use an unknown `version`. - # - MUST fail the payment if any mandatory field (`p`, `h`, `s`, `n`) does not have the correct length (52, 52, 52, 53). + # - 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). data_length = len(tagdata) / 5 if tag == 'r': @@ -392,7 +393,7 @@ def decode(cls, b): # BOLT #11: # 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. inv.signature = inv.pubkey.ecdsa_deserialize_compact(sigdecoded[0:64]) if not inv.pubkey.ecdsa_verify(bytearray([ord(c) for c in hrp]) + data.tobytes(), inv.signature): raise ValueError('Invalid signature') diff --git a/devtools/bolt12-cli.c b/devtools/bolt12-cli.c index a72d57a1d71d..3a81467af996 100644 --- a/devtools/bolt12-cli.c +++ b/devtools/bolt12-cli.c @@ -95,6 +95,7 @@ static bool print_offer_amount(const struct bitcoin_blkid *chains, /* BOLT #12: * - if a specific minimum `offer_amount` is required for successful payment: * - MUST set `offer_amount` to the amount expected (per item). + * - MUST set `offer_amount` greater than zero. * - if the currency for `offer_amount` is that of all entries in `chains`: * - MUST specify `offer_amount` in multiples of the minimum lightning-payable unit * (e.g. milli-satoshis for bitcoin). @@ -150,6 +151,10 @@ static bool print_offer_amount(const struct bitcoin_blkid *chains, currency); } + if (amount == 0) { + printf(" *** INVALID zero offer_amount"); + ok = false; + } return ok; } diff --git a/doc/contribute-to-core-lightning/release-checklist.md b/doc/contribute-to-core-lightning/release-checklist.md index 89abf4067acf..42b0ecac5afb 100644 --- a/doc/contribute-to-core-lightning/release-checklist.md +++ b/doc/contribute-to-core-lightning/release-checklist.md @@ -99,10 +99,16 @@ Here's a checklist for the release process. ## Post-release -1. Create a PR to update Makefile's CLN_NEXT_VERSION and important dates for the next release on `.github/PULL_REQUEST_TEMPLATE.md`. +1. Create a PR to update: + * `Makefile`: variables CLN_NEXT_VERSION and CLN_PREV_VERSION (this may break tests as deprecated things are disabled!) + * `tools/lightningd-downgrade.c`: to downgrade to the just-released version. + * `.github/workflows/ci.yaml`: change old-cln to download the just-released version. + * `.github/PULL_REQUEST_TEMPLATE.md` for important dates for the next release. 2. Look through PRs which were delayed for release and merge them. 3. Close out the Milestone for the now-shipped release. 4. Update this file with any missing or changed instructions. +5. Fetch the latest bolt revision in ../bolts. Then run `./devtools/bolt-catchup.sh` to update BOLTVERSION in the Makefile and run `make check-bolt-quotes`. It may get confused by merges in the BOLTs repository, so you may have to do some manual work. Note: this step may involve a significant amount of work for new spec changes! +6. Go through `doc/developers-guide/deprecated-features.md` and remove features and code whose `Last Supported` was the prior version (i.e. now two versions ago: we give one version where the user can use `i-promise-to-fix-broken-api-user=FEATURENAME` to re-enable it). Also remove the features from any schemas and other documentation. ## Performing the Point (hotfix) Release diff --git a/doc/developers-guide/deprecated-features.md b/doc/developers-guide/deprecated-features.md index be44a5837157..acbb3184e8b4 100644 --- a/doc/developers-guide/deprecated-features.md +++ b/doc/developers-guide/deprecated-features.md @@ -9,7 +9,6 @@ privacy: | Name | Type | First Deprecated | Last Supported | Description | |----------------------------------------------------|--------------------|------------------|----------------|---------------------------------------------------------------------------------------------------------------------------| -| xpay.ignore_bolt12_mpp | Field | v25.05 | v25.12 | Try MPP even if the BOLT12 invoice doesn't explicitly allow it (CLN didn't until 25.02) | | listpeerchannels.max_total_htlc_in_msat | Field | v25.02 | v26.04 | Use our_max_total_htlc_out_msat | | wait.details | Field | v25.05 | v26.06 | Use subsystem-specific object instead | | channel_state_changed.old_state.unknown | Notification Field | v25.05 | v26.04 | Value "unknown" is deprecated: field will be omitted instead | diff --git a/gossipd/gossmap_manage.c b/gossipd/gossmap_manage.c index 91a24757643b..82a20a8bd617 100644 --- a/gossipd/gossmap_manage.c +++ b/gossipd/gossmap_manage.c @@ -1455,12 +1455,12 @@ void gossmap_manage_channel_spent(struct gossmap_manage *gm, /* BOLT #7: * - once its funding output has been spent OR reorganized out: - * - SHOULD forget a channel after a 12-block delay. + * - SHOULD forget a channel after a 72-block delay. */ - cd.deadline = blockheight + 12; + cd.deadline = blockheight + 72; cd.scid = scid; - /* Remember locally so we can kill it in 12 blocks */ + /* Remember locally so we can kill it in 72 blocks */ status_trace("channel %s closing soon due" " to the funding outpoint being spent", fmt_short_channel_id(tmpctx, scid)); diff --git a/hsmd/libhsmd.c b/hsmd/libhsmd.c index f8d35a044ca6..c605198a056f 100644 --- a/hsmd/libhsmd.c +++ b/hsmd/libhsmd.c @@ -1016,13 +1016,12 @@ static u8 *handle_sign_invoice(struct hsmd_client *c, const u8 *msg_in) /* 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}. */ /* FIXME: Check invoice! */ diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 0d482c24e729..820bf4ed6e34 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -160,8 +160,7 @@ wallet_commit_channel(struct lightningd *ld, * #### Requirements * * Both peers: - * ... - * - MUST use that `channel_type` for all commitment transactions. + * - MUST use the negotiated `channel_type` for all commitment transactions. */ /* i.e. We set it now for the channel permanently. */ if (channel_type_has(type, OPT_STATIC_REMOTEKEY)) diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 20ae07c62083..e7da540dab70 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -2430,9 +2430,8 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) /* BOLT #2: * The receiving node MUST fail the channel if: *... - * - It supports `channel_type` and `channel_type` was set: - * - if `type` is not suitable. - * - if `type` includes `option_zeroconf` and it does not trust the sender to open an unconfirmed channel. + * - the `channel_type` is not suitable. + * - the `channel_type` includes `option_zeroconf` and it does not trust the sender to open an unconfirmed channel. */ if (!open_tlv->channel_type) { negotiation_failed(state, @@ -2682,8 +2681,7 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) } /* BOLT #2: - * - if `option_channel_type` was negotiated: - * - MUST set `channel_type` to the `channel_type` from `open_channel` + * - MUST set `channel_type` to the `channel_type` from `open_channel` */ a_tlv->channel_type = state->channel_type->features; @@ -3143,8 +3141,7 @@ static void opener_start(struct state *state, u8 *msg) } /* BOLT #2: - * - if `channel_type` is set, and `channel_type` was set in - * `open_channel`, and they are not equal types: + * if `channel_type` does not match the `channel_type` from `open_channel`: * - MUST fail the channel. */ if (!a_tlv->channel_type) { @@ -3973,13 +3970,10 @@ static void do_reconnect_dance(struct state *state) /* BOLT #2: * - * - if it has sent `commitment_signed` for an - * interactive transaction construction but it has - * not received `tx_signatures`: - * - MUST set `next_funding_txid` to the txid of that - * interactive transaction. - * - otherwise: - * - MUST NOT set `next_funding_txid`. + * - if it has sent `commitment_signed` for an interactive transaction construction but + * it has not received `tx_signatures`: + * - MUST include the `next_funding` TLV. + * - MUST set `next_funding_txid` to the txid of that interactive transaction. */ tlvs = tlv_channel_reestablish_tlvs_new(tmpctx); if (!tx_state->remote_funding_sigs_rcvd) { @@ -4044,10 +4038,11 @@ static void do_reconnect_dance(struct state *state) /* BOLT #2: * A receiving node: - * - if `next_funding_txid` is set: + * - if the `next_funding` TLV is set: * - if `next_funding_txid` matches the latest interactive funding transaction: * - if it has not received `tx_signatures` for that funding transaction: - * - MUST retransmit its `commitment_signed` for that funding transaction. + * - if the `commitment_signed` bit is set in `retransmit_flags`: + * - MUST retransmit its `commitment_signed` for that funding transaction. * - if it has already received `commitment_signed` and it should sign first, * as specified in the [`tx_signatures` requirements](#the-tx_signatures-message): * - MUST send its `tx_signatures` for that funding transaction. @@ -4073,6 +4068,7 @@ static void do_reconnect_dance(struct state *state) if (!tx_state->has_commitments) send_our_sigs = false; } + /* FIXME: examine retransmit_flags! */ if (send_our_sigs && psbt_side_finalized(tx_state->psbt, state->our_role)) { msg = psbt_to_tx_sigs_msg(NULL, state, tx_state->psbt); peer_write(state->pps, take(msg)); diff --git a/openingd/openingd.c b/openingd/openingd.c index cc51e1e67c51..52e50572e2e0 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -332,7 +332,7 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags, = state->upfront_shutdown_script[LOCAL]; /* BOLT #2: - * - if it includes `channel_type`: + * - MUST set `channel_type`: * - MUST set it to a defined type representing the type it wants. * - MUST use the smallest bitmap possible to represent the channel * type. @@ -410,9 +410,8 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags, their_mindepth); /* BOLT #2: - * - if `option_channel_type` was negotiated but the message doesn't - * include a `channel_type`: - * - MAY fail the channel. + * - if the message doesn't include a `channel_type`: + * - MUST fail the channel. */ if (!accept_tlvs->channel_type) { negotiation_failed(state, @@ -420,8 +419,7 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags, } /* BOLT #2: - * - if `channel_type` is set, and `channel_type` was set in - * `open_channel`, and they are not equal types: + * - if `channel_type` does not match the `channel_type` from `open_channel`: * - MUST fail the channel. */ /* Simple case: caller specified, don't allow any variants */ @@ -881,18 +879,20 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) set_remote_upfront_shutdown(state, open_tlvs->upfront_shutdown_script); /* BOLT #2: - * The receiving node MUST fail the channel if: - *... - * - It supports `channel_type` and `channel_type` was set: - * - if `type` is not suitable. - * - if `type` includes `option_zeroconf` and it does not trust the sender to open an unconfirmed channel. + * - if the message doesn't include a `channel_type`: + * - fail the channel. */ - /* option_channel_type is compulsory. */ if (!open_tlvs->channel_type) { negotiation_failed(state, "Did not set channel_type in open_channel message"); } + /* BOLT #2: + * The receiving node MUST fail the channel if: + *... + * - the `channel_type` is not suitable. + * - the `channel_type` includes `option_zeroconf` and it does not trust the sender to open an unconfirmed channel. + */ state->channel_type = channel_type_accept( state, open_tlvs->channel_type, state->our_features); if (!state->channel_type) { @@ -1050,7 +1050,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) /* BOLT #2: * The receiving node MUST fail the channel if: *... - * - if `type` includes `option_zeroconf` and it does not trust the + * - the `channel_type` includes `option_zeroconf` and it does not trust the * sender to open an unconfirmed channel. */ if (channel_type_has(state->channel_type, OPT_ZEROCONF) && @@ -1077,8 +1077,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) accept_tlvs->upfront_shutdown_script = state->upfront_shutdown_script[LOCAL]; /* BOLT #2: - * - if `option_channel_type` was negotiated: - * - MUST set `channel_type` to the `channel_type` from `open_channel` + * - MUST set `channel_type` to the `channel_type` from `open_channel` */ accept_tlvs->channel_type = state->channel_type->features; diff --git a/plugins/offers.c b/plugins/offers.c index 436a32f4ea7c..6c049334c7d9 100644 --- a/plugins/offers.c +++ b/plugins/offers.c @@ -538,7 +538,10 @@ static u8 *encrypted_decode(const tal_t *ctx, const char *str, char **fail) { goto fail; } u8 *data8bit = tal_arr(data, u8, 0); - bech32_pull_bits(&data8bit, data, datalen*5); + if (!bech32_pull_bits(&data8bit, data, datalen*5)) { + *fail = tal_fmt(ctx, "invalid bech32 padding"); + goto fail; + } return data8bit; fail: diff --git a/plugins/xpay/xpay.c b/plugins/xpay/xpay.c index f3a518c11367..05d001d80323 100644 --- a/plugins/xpay/xpay.c +++ b/plugins/xpay/xpay.c @@ -2033,10 +2033,15 @@ static struct command_result *xpay_core(struct command *cmd, * paths, we just know the cltv we use to enter the * final hop. */ payment->final_cltv = 0; - /* We will start honoring this flag in future */ + /* BOLT #12: + * - if `invoice_features` contains the MPP/compulsory bit: + * - MUST pay the invoice via multiple separate blinded paths. + * - otherwise, if `invoice_features` contains the MPP/optional bit: + * - MAY pay the invoice via multiple separate payments. + * - otherwise: + * - MUST NOT use multiple parts to pay the invoice. + */ payment->disable_mpp = !feature_offered(b12inv->invoice_features, OPT_BASIC_MPP); - if (payment->disable_mpp && command_deprecated_in_ok(cmd, "ignore_bolt12_mpp", "v25.05", "v25.12")) - payment->disable_mpp = false; } else { struct bolt11 *b11 = bolt11_decode(tmpctx, payment->invstring, diff --git a/tests/test_connection.py b/tests/test_connection.py index f868b31cdc82..c1abc69ca246 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -4069,7 +4069,7 @@ def test_multichan(node_factory, executor, bitcoind): l2.rpc.close(l3.info['id']) l2.rpc.close(scid23b) - bitcoind.generate_block(13, wait_for_mempool=1) + bitcoind.generate_block(73, wait_for_mempool=1) sync_blockheight(bitcoind, [l1, l2, l3]) # Gossip works as expected. @@ -4120,7 +4120,7 @@ def test_multichan(node_factory, executor, bitcoind): "id": 2, "created_index": 3, "updated_index": 27, - "expiry": 135, + "expiry": 195, "direction": "out", "amount_msat": Millisatoshi(100001001), "payment_hash": inv3['payment_hash'], @@ -4129,7 +4129,7 @@ def test_multichan(node_factory, executor, bitcoind): "id": 3, "created_index": 4, "updated_index": 36, - "expiry": 135, + "expiry": 195, "direction": "out", "amount_msat": Millisatoshi(100001001), "payment_hash": inv4['payment_hash'], diff --git a/tests/test_db.py b/tests/test_db.py index b186ee35eb71..98b3446762b5 100644 --- a/tests/test_db.py +++ b/tests/test_db.py @@ -96,7 +96,7 @@ def test_block_backfill(node_factory, bitcoind, chainparams): # Now close the channel and make sure `l3` cleans up correctly: txid = only_one(l1.rpc.close(l2.info['id'])['txids']) - bitcoind.generate_block(13, wait_for_mempool=txid) + bitcoind.generate_block(73, wait_for_mempool=txid) wait_for(lambda: len(l3.rpc.listchannels()['channels']) == 0) diff --git a/tests/test_gossip.py b/tests/test_gossip.py index 688604da7774..e55492cddd6f 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -581,8 +581,8 @@ def non_public(node): l1.rpc.dev_fail(l2.info['id']) # We need to wait for the unilateral close to hit the mempool, - # and 12 blocks for nodes to actually forget it. - bitcoind.generate_block(13, wait_for_mempool=1) + # and 72 blocks for nodes to actually forget it. + bitcoind.generate_block(73, wait_for_mempool=1) wait_for(lambda: active(l1) == [scid23, scid23]) wait_for(lambda: active(l2) == [scid23, scid23]) @@ -1445,7 +1445,7 @@ def test_gossip_notices_close(node_factory, bitcoind): txid = only_one(l2.rpc.close(l3.info['id'])['txids']) wait_for(lambda: l2.rpc.listpeerchannels(l3.info['id'])['channels'][0]['state'] == 'CLOSINGD_COMPLETE') - bitcoind.generate_block(13, txid) + bitcoind.generate_block(73, txid) wait_for(lambda: l1.rpc.listchannels()['channels'] == []) wait_for(lambda: l1.rpc.listnodes()['nodes'] == []) @@ -1683,7 +1683,7 @@ def test_gossip_store_compact_while_extending(node_factory, bitcoind, executor): scid23 = only_one(l2.rpc.listpeerchannels(l3.info['id'])['channels'])['short_channel_id'] l2.rpc.close(l3.info['id']) - bitcoind.generate_block(13, wait_for_mempool=1) + bitcoind.generate_block(73, wait_for_mempool=1) wait_for(lambda: l1.rpc.listchannels(scid23) == {'channels': []}) l1.rpc.setchannel(l2.info['id'], 41, 1004) @@ -2008,7 +2008,7 @@ def test_topology_leak(node_factory, bitcoind): # Close and wait for gossip to catchup. txid = only_one(l2.rpc.close(l3.info['id'])['txids']) - bitcoind.generate_block(13, txid) + bitcoind.generate_block(73, txid) wait_for(lambda: len(l1.rpc.listchannels()['channels']) == 2) @@ -2035,7 +2035,7 @@ def test_parms_listforwards(node_factory): assert len(forwards_dep) == 0 -def test_close_12_block_delay(node_factory, bitcoind): +def test_close_72_block_delay(node_factory, bitcoind): l1, l2, l3, l4 = node_factory.line_graph(4, wait_for_announce=True) # Close l1-l2 @@ -2052,16 +2052,16 @@ def test_close_12_block_delay(node_factory, bitcoind): # BOLT #7: # - once its funding output has been spent OR reorganized out: - # - SHOULD forget a channel after a 12-block delay. + # - SHOULD forget a channel after a 72-block delay. - # That implies 12 blocks *after* spending, i.e. 13 blocks deep! + # That implies 72 blocks *after* spending, i.e. 73 blocks deep! - # 12 blocks deep, l4 still sees it - bitcoind.generate_block(10) + # 72 blocks deep, l4 still sees it + bitcoind.generate_block(70) sync_blockheight(bitcoind, [l4]) assert len(l4.rpc.listchannels(source=l1.info['id'])['channels']) == 1 - # 13 blocks deep does it. + # 73 blocks deep does it. bitcoind.generate_block(1) wait_for(lambda: l4.rpc.listchannels(source=l1.info['id'])['channels'] == []) @@ -2490,7 +2490,7 @@ def test_gossmap_lost_node(node_factory, bitcoind): scid23 = only_one(l2.rpc.listpeerchannels(l3.info['id'])['channels'])['short_channel_id'] l2.rpc.close(l3.info['id']) - bitcoind.generate_block(13, wait_for_mempool=1) + bitcoind.generate_block(73, wait_for_mempool=1) # Order of nodes is not stable. sync_blockheight(bitcoind, [l1]) @@ -2522,6 +2522,6 @@ def test_gossip_dying_when_compact(node_factory, bitcoind): wait_for(lambda: len(l1.rpc.listchannels()["channels"]) == 4) l1.rpc.call("dev-compact-gossip-store") - # Now actually close it (12 deep) - bitcoind.generate_block(11) + # Now actually close it (72 deep) + bitcoind.generate_block(71) wait_for(lambda: len(l1.rpc.listchannels()["channels"]) == 2) diff --git a/tests/test_invoices.py b/tests/test_invoices.py index 4b67c9aa79c3..161fbd08931e 100644 --- a/tests/test_invoices.py +++ b/tests/test_invoices.py @@ -362,7 +362,7 @@ def test_invoice_routeboost_private(node_factory, bitcoind): # It will use an explicit exposeprivatechannels even if it thinks its a dead-end l0.rpc.close(l1.info['id']) l0.wait_for_channel_onchain(l1.info['id']) - bitcoind.generate_block(13) + bitcoind.generate_block(73) wait_for(lambda: l2.rpc.listchannels(scid_dummy)['channels'] == []) inv = l2.rpc.invoice(amount_msat=123456, label="inv7", description="?", exposeprivatechannels=scid) diff --git a/tests/test_pay.py b/tests/test_pay.py index cc22f26b8f4f..2d0c30f828fc 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -5891,7 +5891,7 @@ def test_offer_paths(node_factory, bitcoind): # Make scid path invalid by closing it close = l1.rpc.close(paths[0]['first_scid']) - bitcoind.generate_block(13, wait_for_mempool=only_one(close['txids'])) + bitcoind.generate_block(73, wait_for_mempool=only_one(close['txids'])) wait_for(lambda: l5.rpc.listchannels(paths[0]['first_scid']) == {'channels': []}) # Now connect l5->l4, and it will be able to reach l3 via that, and join blinded path. diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 3f4f11cbe90f..2a40d4757995 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -4320,7 +4320,7 @@ def test_sql(node_factory, bitcoind): # This has to wait for the hold_invoice plugin to let go! open(os.path.join(l3.daemon.lightning_dir, TEST_NETWORK, "unhold"), "w").close() txid = only_one(l1.rpc.close(l2.info['id'])['txids']) - bitcoind.generate_block(13, wait_for_mempool=txid) + bitcoind.generate_block(73, wait_for_mempool=txid) wait_for(lambda: len(l3.rpc.listchannels(source=l1.info['id'])['channels']) == 0) assert len(l3.rpc.sql("SELECT * FROM channels WHERE source = X'{}';".format(l1.info['id']))['rows']) == 0 l3.daemon.wait_for_log("Deleting channel: {}".format(scid)) @@ -4395,7 +4395,7 @@ def test_sql(node_factory, bitcoind): def test_sql_deprecated(node_factory, bitcoind): - l1, l2 = node_factory.line_graph(2, opts=[{'allow-deprecated-apis': True, "broken_log": "DEPRECATED API USED: listpeerchannels.max_total_htlc_in_msat"}, {}]) + l1, l2 = node_factory.line_graph(2, opts=[{'i-promise-to-fix-broken-api-user': 'listpeerchannels.max_total_htlc_in_msat'}, {}]) # With deprecated APIs, this is there. ret = l1.rpc.sql("SELECT max_total_htlc_in_msat FROM peerchannels;") diff --git a/tests/test_splicing.py b/tests/test_splicing.py index 458f432f8630..f713ff7ba14e 100644 --- a/tests/test_splicing.py +++ b/tests/test_splicing.py @@ -229,7 +229,7 @@ def test_splice_gossip(node_factory, bitcoind): bitcoind.generate_block(5, wait_for_mempool=result['txid']) - # l3 will see channel dying, but still consider it OK for 12 blocks. + # l3 will see channel dying, but still consider it OK for 72 blocks. l3.daemon.wait_for_log(f'gossipd: channel {pre_splice_scid} closing soon due to the funding outpoint being spent') assert len(l3.rpc.listchannels(short_channel_id=pre_splice_scid)['channels']) == 2 assert len(l3.rpc.listchannels(source=l1.info['id'])['channels']) == 1 @@ -246,7 +246,7 @@ def test_splice_gossip(node_factory, bitcoind): wait_for(lambda: len(l3.rpc.listchannels(short_channel_id=post_splice_scid)['channels']) == 2) assert len(l3.rpc.listchannels(short_channel_id=pre_splice_scid)['channels']) == 2 - bitcoind.generate_block(7) + bitcoind.generate_block(67) # The old channel should fall off l3's perspective wait_for(lambda: l3.rpc.listchannels(short_channel_id=pre_splice_scid)['channels'] == []) diff --git a/tests/test_wallet.py b/tests/test_wallet.py index 5be686d11ef4..e4d1cc4fdd66 100644 --- a/tests/test_wallet.py +++ b/tests/test_wallet.py @@ -2562,7 +2562,7 @@ def test_unspend_during_reorg(node_factory, bitcoind): # Now, l3 sees the close, marks channel dying. l1.rpc.close(l2.info['id']) spentheight = bitcoind.rpc.getblockcount() + 1 - bitcoind.generate_block(14, wait_for_mempool=1) + bitcoind.generate_block(74, wait_for_mempool=1) wait_for(lambda: len(l3.rpc.listchannels()['channels']) == 2) # In one fell swoop it goes through dying, to dead (12 blocks) @@ -2576,12 +2576,10 @@ def test_unspend_during_reorg(node_factory, bitcoind): # Restart, see replay. l3.stop() # This is enough to take channel from dying to dead. - bitcoind.generate_block(10) + bitcoind.generate_block(70) l3.start() # Channel should still be dead. - l3.daemon.wait_for_log(f"Adding block {spentheight}") - sync_blockheight(bitcoind, [l3]) assert only_one(l3.db_query(f"SELECT spendheight as spendheight FROM utxoset WHERE blockheight={blockheight} AND txindex={txindex}"))['spendheight'] == spentheight diff --git a/tests/test_xpay.py b/tests/test_xpay.py index 3ba800667920..db4fde9f18c1 100644 --- a/tests/test_xpay.py +++ b/tests/test_xpay.py @@ -637,15 +637,10 @@ def test_xpay_no_mpp(node_factory, chainparams): assert ret['amount_sent_msat'] == AMOUNT + AMOUNT // 100000 + 1 -@pytest.mark.parametrize("deprecations", [False, True]) -def test_xpay_bolt12_no_mpp(node_factory, chainparams, deprecations): +def test_xpay_bolt12_no_mpp(node_factory, chainparams): """If we force it, we use MPP even if BOLT12 invoice doesn't say we should""" # l4 needs dev-allow-localhost so it considers itself to have an advertized address, and doesn't create a blinded path from l2/l4. opts = [{}, {}, {'dev-force-features': -17, 'dev-allow-localhost': None}, {}] - if deprecations is True: - for o in opts: - o['i-promise-to-fix-broken-api-user'] = 'xpay.ignore_bolt12_mpp' - o['broken_log'] = 'DEPRECATED API USED: xpay.ignore_bolt12_mpp' l1, l2, l3, l4 = node_factory.get_nodes(4, opts=opts) node_factory.join_nodes([l1, l2, l3], wait_for_announce=True) @@ -666,12 +661,8 @@ def test_xpay_bolt12_no_mpp(node_factory, chainparams, deprecations): ret = l1.rpc.xpay(invl3['invoice']) assert ret['failed_parts'] == 0 - if deprecations: - assert ret['successful_parts'] == 2 - assert ret['amount_sent_msat'] == AMOUNT + AMOUNT // 100000 + 2 - else: - assert ret['successful_parts'] == 1 - assert ret['amount_sent_msat'] == AMOUNT + AMOUNT // 100000 + 1 + assert ret['successful_parts'] == 1 + assert ret['amount_sent_msat'] == AMOUNT + AMOUNT // 100000 + 1 assert ret['amount_msat'] == AMOUNT diff --git a/tools/gen/impl_template b/tools/gen/impl_template index c3b97d5f517d..7308aac69601 100644 --- a/tools/gen/impl_template +++ b/tools/gen/impl_template @@ -91,7 +91,7 @@ ${fieldname} = tal_arr(${ctx}, ${typename}, ${f.size('*plen')}); fromwire_${type_}_array(cursor, plen, ${fieldname}, ${f.size('*plen')}); % else: % if f.is_varlen(): -${fieldname} = ${f.size('*plen')} ? tal_arr(${ctx}, ${typename}, 0) : NULL; +${fieldname} = tal_arr(${ctx}, ${typename}, 0); % endif % if f.is_implicit_len(): while (*plen != 0) { diff --git a/tools/lightning-downgrade.c b/tools/lightning-downgrade.c index 25a118de04e6..70a8f2206e5b 100644 --- a/tools/lightning-downgrade.c +++ b/tools/lightning-downgrade.c @@ -169,6 +169,7 @@ static const char *downgrade_askrene_layers(const tal_t *ctx, struct db *db) static const struct db_version db_versions[] = { { "v25.09", 276, downgrade_askrene_layers, false }, { "v25.12", 280, NULL, false }, + { "v26.04", 282, NULL, false }, }; static const struct db_version *version_db(const char *version) diff --git a/wallet/migrations.c b/wallet/migrations.c index 83c61c0e9129..1f5d3b51c0f2 100644 --- a/wallet/migrations.c +++ b/wallet/migrations.c @@ -1084,6 +1084,7 @@ static const struct db_migration dbmigrations[] = { NULL, NULL}, {SQL("ALTER TABLE offers ADD COLUMN force_paths INTEGER DEFAULT 0;"), NULL, SQL("ALTER TABLE offers DROP COLUMN force_paths"), NULL}, + /* ^v26.04 */ }; const struct db_migration *get_db_migrations(size_t *num) diff --git a/wire/extracted_peer-shutdown-wrong_funding.patch b/wire/extracted_peer-shutdown-wrong_funding.patch index 114380237c4e..ec8f52393559 100644 --- a/wire/extracted_peer-shutdown-wrong_funding.patch +++ b/wire/extracted_peer-shutdown-wrong_funding.patch @@ -8,6 +8,6 @@ +tlvtype,shutdown_tlvs,wrong_funding,100 +tlvdata,shutdown_tlvs,wrong_funding,txid,sha256, +tlvdata,shutdown_tlvs,wrong_funding,outnum,u32, - msgtype,closing_signed,39 - msgdata,closing_signed,channel_id,channel_id, - msgdata,closing_signed,fee_satoshis,u64, + msgtype,closing_complete,40 + msgdata,closing_complete,channel_id,channel_id, + msgdata,closing_complete,closer_scriptpubkey_len,u16, diff --git a/wire/extracted_peer_11_splice.patch b/wire/extracted_peer_11_splice.patch index 13190f572f94..09a76c942683 100644 --- a/wire/extracted_peer_11_splice.patch +++ b/wire/extracted_peer_11_splice.patch @@ -1,8 +1,15 @@ -diff --git a/wire/peer_wire.csv b/wire/peer_wire.csv -index 5b5803afc..41b57e85b 100644 ---- a/wire/peer_wire.csv -+++ b/wire/peer_wire.csv -@@ -206,6 +206,19 @@ subtypedata,lease_rates,channel_fee_max_base_msat,tu32, +diff --git b/wire/peer_wire.csv a/wire/peer_wire.csv +index f3a42e5537..4b01c56836 100644 +--- b/wire/peer_wire.csv ++++ a/wire/peer_wire.csv +@@ -1,3 +1,6 @@ ++msgtype,protocol_batch_element,0 ++msgdata,protocol_batch_element,channel_id,channel_id, ++msgdata,protocol_batch_element,element_size,u16, + msgtype,init,16 + msgdata,init,gflen,u16, + msgdata,init,globalfeatures,byte,gflen +@@ -217,6 +220,19 @@ subtypedata,lease_rates,channel_fee_max_base_msat,tu32, msgtype,stfu,2 msgdata,stfu,channel_id,channel_id, msgdata,stfu,initiator,u8, @@ -22,25 +29,34 @@ index 5b5803afc..41b57e85b 100644 msgtype,shutdown,38 msgdata,shutdown,channel_id,channel_id, msgdata,shutdown,len,u16, -@@ -264,6 +250,10 @@ msgdata,commitment_signed,channel_id,channel_id, +@@ -280,11 +296,20 @@ msgdata,update_fail_malformed_htlc,channel_id,channel_id, + msgdata,update_fail_malformed_htlc,id,u64, + msgdata,update_fail_malformed_htlc,sha256_of_onion,sha256, + msgdata,update_fail_malformed_htlc,failure_code,u16, ++msgtype,start_batch,127 ++msgdata,start_batch,channel_id,channel_id, ++msgdata,start_batch,batch_size,u16, ++msgdata,start_batch,batch_info,start_batch_tlvs, ++tlvtype,start_batch_tlvs,batch_info,1 ++tlvdata,start_batch_tlvs,batch_info,message_type,u16, + msgtype,commitment_signed,132 + msgdata,commitment_signed,channel_id,channel_id, msgdata,commitment_signed,signature,signature, msgdata,commitment_signed,num_htlcs,u16, msgdata,commitment_signed,htlc_signature,signature,num_htlcs +msgdata,commitment_signed,splice_channel_id,commitment_signed_tlvs, -+tlvtype,commitment_signed_tlvs,splice_info,0 -+tlvdata,commitment_signed_tlvs,splice_info,batch_size,u16, ++tlvtype,commitment_signed_tlvs,splice_info,1 +tlvdata,commitment_signed_tlvs,splice_info,funding_txid,sha256, msgtype,revoke_and_ack,133 msgdata,revoke_and_ack,channel_id,channel_id, msgdata,revoke_and_ack,per_commitment_secret,byte,32 -@@ -319,6 +320,10 @@ msgdata,channel_reestablish,your_last_per_commitment_secret,byte,32 - msgdata,channel_reestablish,my_current_per_commitment_point,point, - tlvtype,channel_reestablish_tlvs,next_funding,0 +@@ -301,6 +326,9 @@ msgdata,channel_reestablish,next_commitment_number,u64, + tlvtype,channel_reestablish_tlvs,next_funding,1 tlvdata,channel_reestablish_tlvs,next_funding,next_funding_txid,sha256, -+tlvtype,channel_reestablish_tlvs,your_last_funding_locked_txid,1 -+tlvdata,channel_reestablish_tlvs,your_last_funding_locked_txid,your_last_funding_locked_txid,sha256, -+tlvtype,channel_reestablish_tlvs,my_current_funding_locked_txid,3 -+tlvdata,channel_reestablish_tlvs,my_current_funding_locked_txid,my_current_funding_locked_txid,sha256, + tlvdata,channel_reestablish_tlvs,next_funding,retransmit_flags,byte, ++tlvtype,channel_reestablish_tlvs,my_current_funding_locked,5 ++tlvdata,channel_reestablish_tlvs,my_current_funding_locked,my_current_funding_locked_txid,sha256, ++tlvdata,channel_reestablish_tlvs,my_current_funding_locked,retransmit_flags,byte, msgtype,announcement_signatures,259 msgdata,announcement_signatures,channel_id,channel_id, msgdata,announcement_signatures,short_channel_id,short_channel_id, diff --git a/wire/extracted_peer_12_splice_update.patch b/wire/extracted_peer_12_splice_update.patch deleted file mode 100644 index 96a8a8f88ebd..000000000000 --- a/wire/extracted_peer_12_splice_update.patch +++ /dev/null @@ -1,33 +0,0 @@ -diff --git a/wire/peer_wire.csv b/wire/peer_wire.csv -index 9abcb0e64..e2aae8efb 100644 ---- a/wire/peer_wire.csv -+++ b/wire/peer_wire.csv -@@ -1,3 +1,6 @@ -+msgtype,protocol_batch_element,0 -+msgdata,protocol_batch_element,channel_id,channel_id, -+msgdata,protocol_batch_element,element_size,u16, - msgtype,init,16 - msgdata,init,gflen,u16, - msgdata,init,globalfeatures,byte,gflen -@@ -293,6 +296,12 @@ msgdata,update_fail_malformed_htlc,channel_id,channel_id, - msgdata,update_fail_malformed_htlc,id,u64, - msgdata,update_fail_malformed_htlc,sha256_of_onion,sha256, - msgdata,update_fail_malformed_htlc,failure_code,u16, -+msgtype,start_batch,127 -+msgdata,start_batch,channel_id,channel_id, -+msgdata,start_batch,batch_size,u16, -+msgdata,start_batch,batch_info,start_batch_tlvs, -+tlvtype,start_batch_tlvs,batch_info,1 -+tlvdata,start_batch_tlvs,batch_info,message_type,u16, - msgtype,commitment_signed,132 - msgdata,commitment_signed,channel_id,channel_id, - msgdata,commitment_signed,signature,signature, -@@ -309,7 +309,6 @@ msgdata,commitment_signed,num_htlcs,u16, - msgdata,commitment_signed,htlc_signature,signature,num_htlcs - msgdata,commitment_signed,splice_channel_id,commitment_signed_tlvs, --tlvtype,commitment_signed_tlvs,splice_info,0 --tlvdata,commitment_signed_tlvs,splice_info,batch_size,u16, -+tlvtype,commitment_signed_tlvs,splice_info,1 - tlvdata,commitment_signed_tlvs,splice_info,funding_txid,sha256, - msgtype,revoke_and_ack,133 - msgdata,revoke_and_ack,channel_id,channel_id, diff --git a/wire/peer_wire.csv b/wire/peer_wire.csv index 4b01c56836cc..1dad37d9b7f3 100644 --- a/wire/peer_wire.csv +++ b/wire/peer_wire.csv @@ -241,14 +241,6 @@ msgdata,shutdown,tlvs,shutdown_tlvs, tlvtype,shutdown_tlvs,wrong_funding,100 tlvdata,shutdown_tlvs,wrong_funding,txid,sha256, tlvdata,shutdown_tlvs,wrong_funding,outnum,u32, -msgtype,closing_signed,39 -msgdata,closing_signed,channel_id,channel_id, -msgdata,closing_signed,fee_satoshis,u64, -msgdata,closing_signed,signature,signature, -msgdata,closing_signed,tlvs,closing_signed_tlvs, -tlvtype,closing_signed_tlvs,fee_range,1 -tlvdata,closing_signed_tlvs,fee_range,min_fee_satoshis,u64, -tlvdata,closing_signed_tlvs,fee_range,max_fee_satoshis,u64, msgtype,closing_complete,40 msgdata,closing_complete,channel_id,channel_id, msgdata,closing_complete,closer_scriptpubkey_len,u16, @@ -273,6 +265,14 @@ tlvtype,closing_tlvs,closee_output_only,2 tlvdata,closing_tlvs,closee_output_only,sig,signature, tlvtype,closing_tlvs,closer_and_closee_outputs,3 tlvdata,closing_tlvs,closer_and_closee_outputs,sig,signature, +msgtype,closing_signed,39 +msgdata,closing_signed,channel_id,channel_id, +msgdata,closing_signed,fee_satoshis,u64, +msgdata,closing_signed,signature,signature, +msgdata,closing_signed,tlvs,closing_signed_tlvs, +tlvtype,closing_signed_tlvs,fee_range,1 +tlvdata,closing_signed_tlvs,fee_range,min_fee_satoshis,u64, +tlvdata,closing_signed_tlvs,fee_range,max_fee_satoshis,u64, msgtype,update_add_htlc,128 msgdata,update_add_htlc,channel_id,channel_id, msgdata,update_add_htlc,id,u64,