diff --git a/Makefile b/Makefile index fb1f068d7fe6..7364cffee849 100644 --- a/Makefile +++ b/Makefile @@ -566,19 +566,19 @@ else CHECK_BOLT_COMMIT=--include-commit=$(BOLTVERSION) endif -CHECK_QUOTES := devtools/check_quotes.py +CHECK_QUOTES := greatspectate check --config devtools/specquotes.toml -k BOLT_COVERAGE_FLAGS=$(if $(COVERAGE_FILE),--coverage=$(COVERAGE_FILE),) # Any mention of BOLT# must be followed by an exact quote, modulo whitespace. bolt-check/%: % bolt-precheck - @if [ -d .tmp.lightningrfc ]; then uv run $(CHECK_QUOTES) -k $(CHECK_BOLT_COMMIT) --comment-start "/* " --comment-continue "*" --comment-end "*/" --boltdir .tmp.lightningrfc $(BOLT_COVERAGE_FLAGS) $<; else echo "Not checking BOLTs: BOLTDIR $(BOLTDIR) does not exist" >&2; fi + @if [ -d .tmp.lightningrfc ]; then uv run $(CHECK_QUOTES) -k $(CHECK_BOLT_COMMIT) --comment-start "/* " --comment-continue "*" --comment-end "*/" $(BOLT_COVERAGE_FLAGS) $<; else echo "Not checking BOLTs: BOLTDIR $(BOLTDIR) does not exist" >&2; fi bolt-check-py/%: % bolt-precheck - @if [ -d .tmp.lightningrfc ]; then uv run $(CHECK_QUOTES) -k $(CHECK_BOLT_COMMIT) --boltdir .tmp.lightningrfc $(BOLT_COVERAGE_FLAGS) $<; else echo "Not checking BOLTs: BOLTDIR $(BOLTDIR) does not exist" >&2; fi + @if [ -d .tmp.lightningrfc ]; then uv run $(CHECK_QUOTES) -k $(CHECK_BOLT_COMMIT) $(BOLT_COVERAGE_FLAGS) $<; else echo "Not checking BOLTs: BOLTDIR $(BOLTDIR) does not exist" >&2; fi bolt-check-rs/%: % bolt-precheck - @if [ -d .tmp.lightningrfc ]; then uv run $(CHECK_QUOTES) -k $(CHECK_BOLT_COMMIT) --comment-start "// " --comment-continue "//" --boltdir .tmp.lightningrfc $(BOLT_COVERAGE_FLAGS) $<; else echo "Not checking BOLTs: BOLTDIR $(BOLTDIR) does not exist" >&2; fi + @if [ -d .tmp.lightningrfc ]; then uv run $(CHECK_QUOTES) -k $(CHECK_BOLT_COMMIT) --comment-start "// " --comment-continue "//" $(BOLT_COVERAGE_FLAGS) $<; else echo "Not checking BOLTs: BOLTDIR $(BOLTDIR) does not exist" >&2; fi LOCAL_BOLTDIR=.tmp.lightningrfc @@ -595,7 +595,7 @@ check-requirements-coverage: bolt-precheck @f=/tmp/cln-bolt-coverage.$$$$; \ rm -f $$f; \ $(MAKE) check-source-bolt COVERAGE_FILE=$$f && \ - uv run devtools/bolt-coverage.py --coverage $$f --boltdir .tmp.lightningrfc; \ + uv run greatspectate coverage --config devtools/specquotes.toml --coverage $$f; \ rc=$$?; rm -f $$f; exit $$rc check-whitespace/%: % diff --git a/bitcoin/script.c b/bitcoin/script.c index ede201e9eee6..17e560e1a148 100644 --- a/bitcoin/script.c +++ b/bitcoin/script.c @@ -381,7 +381,7 @@ u8 *scriptpubkey_p2tr_derkey(const tal_t *ctx, const u8 inner_der[33]) * block csv lock. * OP_CHECKSIGVERIFY 1 OP_CHECKSEQUENCEVERIFY */ -/* BOLT- #3 +/* BOLT-liquidity-ads #3: * ##### Leased channel (`option_will_fund`) * * If a `lease` applies to the channel, the `to_remote` output @@ -597,7 +597,7 @@ u8 **bitcoin_witness_sig_and_element(const tal_t *ctx, * OP_ENDIF * OP_CHECKSIG */ -/* BOLT- #3 +/* BOLT-liquidity-ads #3: * ##### Leased channel (`option_will_fund`) * If a `lease` applies to the channel, the `to_local` output of the `accepter` * ensures the `leasor` funds are not spendable until the lease expires. diff --git a/channeld/channeld.c b/channeld/channeld.c index 3848f0d2e837..e0ac240aabc5 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -773,7 +773,7 @@ static void handle_peer_blockheight_change(struct peer *peer, const u8 *msg) "Bad update_blockheight %s", tal_hex(msg, msg)); - /* BOLT- #2: + /* BOLT-liquidity-ads #2: * A receiving node: * ... * - if the sender is not the initiator: @@ -790,7 +790,7 @@ static void handle_peer_blockheight_change(struct peer *peer, const u8 *msg) " our current height %u", blockheight, current, peer->our_blockheight); - /* BOLT- #2: + /* BOLT-liquidity-ads #2: * A receiving node: * - if the `update_blockheight` is less than the last * received `blockheight`: @@ -814,7 +814,7 @@ static void handle_peer_blockheight_change(struct peer *peer, const u8 *msg) "update_blockheight %u older than previous %u", blockheight, current); - /* BOLT- #2: + /* BOLT-liquidity-ads #2: * A receiving node: * ... * - if `blockheight` is more than 1008 blocks behind @@ -2043,13 +2043,13 @@ static struct commitsig_info *handle_peer_commit_sig(struct peer *peer, peer_failed_warn(peer->pps, &peer->channel_id, "Bad commit_sig %s", tal_hex(msg, msg)); - /* BOLT-f9fd539db6cc6f3e532fdc8cc1ebe8eb1a8fd717 + /* BOLT #2: * - If the sending node sent `start_batch` and we are processing a batch of * `commitment_signed` messages: */ if (msg_batch && tal_count(msg_batch) > 1) { - /* BOLT-f9fd539db6cc6f3e532fdc8cc1ebe8eb1a8fd717 + /* BOLT #2: * - If `funding_txid` is missing in one of the `commitment_signed` messages: * - MUST send an `error` and fail the channel. */ @@ -2058,7 +2058,7 @@ static struct commitsig_info *handle_peer_commit_sig(struct peer *peer, "Must send funding_txid when sending" " a commitment batch."); - /* BOLT-f9fd539db6cc6f3e532fdc8cc1ebe8eb1a8fd717 + /* BOLT #2: * - Otherwise (no pending splice transactions): *... * - If `commitment_signed` is missing for the current funding transaction: @@ -2073,7 +2073,7 @@ static struct commitsig_info *handle_peer_commit_sig(struct peer *peer, fmt_bitcoin_txid(tmpctx, &peer->channel->funding.txid)); } - /* BOLT-f9fd539db6cc6f3e532fdc8cc1ebe8eb1a8fd717 + /* BOLT #2: * - If `funding_txid` is missing in one of the `commitment_signed` messages: * - MUST send an `error` and fail the channel. */ @@ -2288,7 +2288,7 @@ static struct commitsig_info *handle_peer_commit_sig(struct peer *peer, tal_count(peer->splice_state->inflights)); commitsigs = tal_arr(NULL, const struct commitsig*, 0); - /* BOLT-f9fd539db6cc6f3e532fdc8cc1ebe8eb1a8fd717 + /* BOLT #2: * - If there are pending splice transactions: * - MUST validate each `commitment_signed` based on `funding_txid`. * - If `commitment_signed` is missing for a funding transaction: @@ -2415,7 +2415,7 @@ static struct commitsig_info *handle_peer_commit_sig_batch(struct peer *peer, peer_failed_warn(peer->pps, &peer->channel_id, "Bad commit_sig %s", tal_hex(msg, msg)); - /* BOLT-f9fd539db6cc6f3e532fdc8cc1ebe8eb1a8fd717 + /* BOLT #2: * - If there are pending splice transactions and the sending node did not * send `start_batch` followed by a batch of `commitment_signed` messages: * - MUST send an `error` and fail the channel. @@ -2461,7 +2461,7 @@ static struct commitsig_info *handle_peer_commit_sig_batch(struct peer *peer, msg_batch[i] = sub_msg; } - /* BOLT-f9fd539db6cc6f3e532fdc8cc1ebe8eb1a8fd717 + /* BOLT #2: * - Otherwise (no pending splice transactions): * - MUST ignore `commitment_signed` where `funding_txid` does not match * the current funding transaction. @@ -3677,7 +3677,7 @@ static struct amount_sat check_balances(struct peer *peer, fmt_amount_sat(tmpctx, max_accepter_fee)); } - /* BOLT-??? #2: + /* BOLT-FIXME #2: * - if either side has added an output other than the new channel * funding output: * - MUST fail the negotiation if the balance for that side is less @@ -3861,9 +3861,10 @@ static void resume_splice_negotiation(struct peer *peer, * 2) other side sneakily adding other outputs we own */ - /* BOLT-a8b9f495cac28124c69cc5ee429f9ef2bacb9921 #2: - * Both nodes: - * - MUST sign the transaction using SIGHASH_ALL */ + /* BOLT #2: + * The sending node: + *... + * - MUST use the `SIGHASH_ALL` (0x01) flag on each signature splice_sig.sighash_type = SIGHASH_ALL; bitcoin_tx = bitcoin_tx_with_psbt(tmpctx, current_psbt); @@ -3994,9 +3995,10 @@ static void resume_splice_negotiation(struct peer *peer, their_sig = tal(tmpctx, struct bitcoin_signature); - /* BOLT-a8b9f495cac28124c69cc5ee429f9ef2bacb9921 #2: - * Both nodes: - * - MUST sign the transaction using SIGHASH_ALL */ + /* BOLT #2: + * The sending node: + *... + * - MUST use the `SIGHASH_ALL` (0x01) flag on each signature their_sig->sighash_type = SIGHASH_ALL; their_sig->s = *their_txsigs_tlvs->shared_input_signature; @@ -5707,7 +5709,7 @@ static void peer_reconnect(struct peer *peer, send_tlvs->next_funding = talz(send_tlvs, struct tlv_channel_reestablish_tlvs_next_funding); send_tlvs->next_funding->next_funding_txid = inflight->outpoint.txid; - /* BOLT-??? #2: + /* BOLT #2: * The `next_funding.retransmit_flags` bitfield is used to let the * receiving peer know which messages they must retransmit for the * corresponding `next_funding_txid` after the reconnection: @@ -5720,7 +5722,7 @@ static void peer_reconnect(struct peer *peer, } } - /* BOLT-??? #2: + /* BOLT #2: * - if `option_splice` was negotiated: */ if (feature_negotiated(peer->our_features, peer->their_features, @@ -5740,7 +5742,7 @@ static void peer_reconnect(struct peer *peer, } } - /* BOLT-??? #2: + /* BOLT #2: * - if a splice transaction reached acceptable depth while disconnected: * - MUST include `my_current_funding_locked` with the txid of the latest such transaction. * - otherwise, if it has already sent `splice_locked` for any transaction: @@ -5755,7 +5757,7 @@ static void peer_reconnect(struct peer *peer, fmt_bitcoin_txid(tmpctx, &peer->splice_state->locked_txid)); } - /* BOLT-??? #2: + /* BOLT #2: * - otherwise, if it has already sent `channel_ready`: * - MUST include `my_current_funding_locked` with the txid of the channel funding transaction. */ @@ -5768,7 +5770,7 @@ static void peer_reconnect(struct peer *peer, fmt_bitcoin_txid(tmpctx, &peer->channel->funding.txid)); } - /* BOLT-??? #2: + /* BOLT #2: * - otherwise (it has never sent `channel_ready` or `splice_locked`): * - MUST NOT include `my_current_funding_locked`. */ @@ -6007,7 +6009,7 @@ static void peer_reconnect(struct peer *peer, peer_write(peer->pps, take(msg)); } - /* BOLT-??? #2 + /* BOLT #2: * A receiving node: * - if splice transactions are pending and `my_current_funding_locked` matches one of * those splice transactions, for which it hasn't received `splice_locked` yet: @@ -6018,7 +6020,7 @@ static void peer_reconnect(struct peer *peer, if (!bitcoin_txid_eq(&itr->outpoint.txid, &recv_tlvs->my_current_funding_locked->my_current_funding_locked_txid)) continue; - /* BOLT-??? #2 + /* BOLT #2: * - MUST process `my_current_funding_locked` as if it was receiving `splice_locked` * for this `txid`. */ @@ -6160,13 +6162,13 @@ static void peer_reconnect(struct peer *peer, if (retransmit_revoke_and_ack && peer->last_was_revoke) resend_revoke(peer); - /* BOLT-splice #2 + /* BOLT #2: * 1. type: 5 (`my_current_funding_locked`) * 2. data: * * [`sha256`:`my_current_funding_locked_txid`] * * [`byte`:`retransmit_flags`] - * - * The `retransmit_flags` bitfield is used to let our peer know which messages + *... + * The `my_current_funding_locked.retransmit_flags` bitfield is used to let our peer know which messages * we expect them to retransmit after the reconnection: * * | Bit Position | Name | @@ -6541,7 +6543,7 @@ static void handle_blockheight(struct peer *peer, const u8 *inmsg) u32 peer_height = get_blockheight(peer->channel->blockheight_states, peer->channel->opener, REMOTE); - /* BOLT- #2: + /* BOLT-liquidity-ads #2: * The node _not responsible_ for initiating the channel: * ... * - if last received `blockheight` is > 1008 behind diff --git a/channeld/commit_tx.c b/channeld/commit_tx.c index 48b614de0376..08800deda135 100644 --- a/channeld/commit_tx.c +++ b/channeld/commit_tx.c @@ -276,7 +276,7 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, * output](#to_local-output). */ if (amount_msat_greater_eq_sat(self_pay, dust_limit)) { - /* BOLT- #3: + /* BOLT-liquidity-ads #3: * In a leased channel, the `to_local` output that * pays the `accepter` node is modified so that its * CSV is equal to the greater of the @@ -331,7 +331,7 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, &keyset->other_payment_key, (!side) == lessor ? csv_lock : 1); - /* BOLT- #3: + /* BOLT-liquidity-ads #3: * ##### Leased channel (`option_will_fund`) * * If a `lease` applies to the channel, the diff --git a/common/bolt12.c b/common/bolt12.c index 3b80f0578376..790500d1c0fc 100644 --- a/common/bolt12.c +++ b/common/bolt12.c @@ -270,7 +270,7 @@ struct tlv_offer *offer_decode(const tal_t *ctx, } } - /* BOLT-recurrence #12 + /* BOLT-recurrence #12: * - if `offer_recurrence_optional` or `offer_recurrence_compulsory` are set: * - if `time_unit` is not one of 0, 1, or 2: * - MUST NOT respond to the offer. @@ -297,7 +297,7 @@ struct tlv_offer *offer_decode(const tal_t *ctx, return tal_free(offer); } } else { - /* BOLT-recurrence #12 + /* BOLT-recurrence: #12 * - otherwise: (no recurrence): * - if it `offer_recurrence_paywindow`, `offer_recurrence_limit` or `offer_recurrence_base` are set: * - MUST NOT respond to the offer. diff --git a/common/channel_config.h b/common/channel_config.h index b796dc1aa96a..55bb5456e0ea 100644 --- a/common/channel_config.h +++ b/common/channel_config.h @@ -74,9 +74,8 @@ struct channel_config { * HTLCs the remote node can offer. */ u16 max_accepted_htlcs; - /* BOLT-TBD #X - * - * maximum dust exposure allowed for this channel + /* BOLT #2: + * ### Bounding exposure to trimmed in-flight HTLCs: `max_dust_htlc_exposure_msat` */ struct amount_msat max_dust_htlc_exposure_msat; }; diff --git a/common/features.h b/common/features.h index a7c833656b4d..8da62acf80e7 100644 --- a/common/features.h +++ b/common/features.h @@ -125,7 +125,7 @@ struct feature_set *feature_set_dup(const tal_t *ctx, * | 50/51 | `option_zeroconf` |... INT ... * | 60/61 | `option_simple_close` |... IN ... */ -/* BOLT-splice #9: +/* BOLT #9: * | 62/63 | `option_splice` |... IN ... */ #define OPT_DATA_LOSS_PROTECT 0 diff --git a/common/interactivetx.c b/common/interactivetx.c index 317a571dc6d0..af8b6fa389ca 100644 --- a/common/interactivetx.c +++ b/common/interactivetx.c @@ -574,7 +574,7 @@ char *process_interactivetx_updates(const tal_t *ctx, "Invalid tx outnum sent. %u", outpoint.n); /* - * BOLT-f53ca2301232db780843e894f55d95d512f297f9 #2: + * BOLT #2: * The receiving node: ... * - MUST fail the negotiation if: ... * - the `prevtx_out` input of `prevtx` is diff --git a/common/lease_rates.c b/common/lease_rates.c index 7bcb3ce0c519..41749697775d 100644 --- a/common/lease_rates.c +++ b/common/lease_rates.c @@ -22,7 +22,7 @@ void lease_rates_get_commitment(const struct pubkey *pubkey, { struct sha256_ctx sctx = SHA256_INIT; u8 der[PUBKEY_CMPR_LEN]; - /* BOLT- #2: + /* BOLT-liquidity-ads #2: * - MUST set `signature` to the ECDSA signature of * SHA256("option_will_fund" * || `funding_pubkey` @@ -47,7 +47,7 @@ bool lease_rates_calc_fee(const struct lease_rates *rates, struct amount_sat *fee) { struct amount_sat lease_fee, basis_sat, tx_fee; - /* BOLT- #2: + /* BOLT-liquidity-ads #2: * The lease fee is calculated as: * `lease_fee_base_sat` + * min(`accept_channel2`.`funding_satoshis`, `open_channel2`.`requested_sats`) * `lease_fee_basis` / 10_000 + diff --git a/common/sciddir_or_pubkey.c b/common/sciddir_or_pubkey.c index 3d47b3a8670b..a613abba0d3c 100644 --- a/common/sciddir_or_pubkey.c +++ b/common/sciddir_or_pubkey.c @@ -4,11 +4,11 @@ #include #include -/* BOLT-sciddir_or_pubkey #1: +/* BOLT #1: * * `sciddir_or_pubkey`: either 9 or 33 bytes referencing or identifying a node, respectively * * if the first byte is 0 or 1, then an 8-byte `short_channel_id` follows for a total of 9 bytes - * * 0 for the first byte indicates this refers to `node_id_1` in the `channel_announcement` for `short_channel_id` (see [BOLT #7](07-routing-gossip.md#the-channel_announcement-message)) - * * 1 for the first byte indicates this refers to `node_id_2` in the `channel_announcement` for `short_channel_id` (see [BOLT #7](07-routing-gossip.md#the-channel_announcement-message)) + * * 0 for the first byte indicates this refers to `node_id_1` in the `channel_announcement` for `short_channel_id` + * * 1 for the first byte indicates this refers to `node_id_2` in the `channel_announcement` for `short_channel_id` (see [BOLT #7](07-routing-gossip.md#the-channel_announcement-message) * * if the first byte is 2 or 3, then the value is a 33-byte `point` */ void towire_sciddir_or_pubkey(u8 **pptr, diff --git a/common/test/run-bolt11.c b/common/test/run-bolt11.c index 1fbc3cec8f9f..96a21c56974e 100644 --- a/common/test/run-bolt11.c +++ b/common/test/run-bolt11.c @@ -591,7 +591,7 @@ int main(int argc, char *argv[]) dev_bolt11_old_order = false; dev_bolt11_omit_c_value = false; - /* BOLT #11 + /* BOLT #11: * * > ### Same, but including fields which must be ignored. * > lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqqsgq2qrqqqfppnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqppnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqhpnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqhp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqspnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnp5qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnpkqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqz599y53s3ujmcfjp5xrdap68qxymkqphwsexhmhr8wdz5usdzkzrse33chw6dlp3jhuhge9ley7j2ayx36kawe7kmgg8sv5ugdyusdcqzn8z9x diff --git a/common/test/run-lease_rates.c b/common/test/run-lease_rates.c index 3e9cd1491730..c7d2e2529915 100644 --- a/common/test/run-lease_rates.c +++ b/common/test/run-lease_rates.c @@ -97,7 +97,7 @@ static void check_lease_rate_commitment_hash(void) static void check_lease_rate_fees(void) { - /* BOLT- #2: + /* BOLT-liquidity-ads #2: * E.g. * An node requests 1_000_000sats at a feerate of 2500perkw. They * are contributing 500_000sats. Their weight contribution to the diff --git a/devtools/specquotes.toml b/devtools/specquotes.toml new file mode 100644 index 000000000000..58df0ce701c1 --- /dev/null +++ b/devtools/specquotes.toml @@ -0,0 +1,4 @@ +[sources.bolt] +format = "markdown" +dir = "../.tmp.lightningrfc" +pattern = "{id:02d}-*.md" diff --git a/gossipd/gossmap_manage.c b/gossipd/gossmap_manage.c index 82a20a8bd617..90941b5fa208 100644 --- a/gossipd/gossmap_manage.c +++ b/gossipd/gossmap_manage.c @@ -648,7 +648,7 @@ const char *gossmap_manage_channel_announcement(const tal_t *ctx, tal_hex(tmpctx, announce)); } - /* BOLT-gossip-node-check #7: + /* BOLT #7: * The receiving node: *... * - if `node_id_1` is not lexicographically less than `node_id_2`: diff --git a/gossipd/seeker.c b/gossipd/seeker.c index 5c5a6bbf1e0c..c24f74c273c3 100644 --- a/gossipd/seeker.c +++ b/gossipd/seeker.c @@ -263,7 +263,7 @@ static void normal_gossip_start(struct seeker *seeker, struct peer *peer, bool a { bool enable_stream = false; - /* BOLT-remove-old-features #7: + /* BOLT #7: * Understanding of messages used to be indicated with the `gossip_queries` * feature bit; now these messages are universally supported, that feature has * now been slightly repurposed. Not offering this feature means a node is not @@ -950,7 +950,7 @@ static bool peer_is_not_gossipper(const struct peer *peer) { const struct seeker *seeker = peer->daemon->seeker; - /* BOLT-remove-old-features #7: + /* BOLT #7: * `gossip_queries`... Not offering this feature means a node is not * worth querying for gossip */ diff --git a/lightningd/invoice.c b/lightningd/invoice.c index 28173383d23d..605d75c21b5f 100644 --- a/lightningd/invoice.c +++ b/lightningd/invoice.c @@ -536,7 +536,7 @@ static struct route_info **select_inchan(const tal_t *ctx, const struct routehint_candidate *candidates) { - /* BOLT-11 struct wants an array of arrays (can provide multiple routes) */ + /* Struct in BOLT-11 wants an array of arrays (can provide multiple routes) */ struct route_info **r = NULL; double total_weight = 0.0; diff --git a/lightningd/invoice.h b/lightningd/invoice.h index 9fee7ec9aed5..138c6d7d75c2 100644 --- a/lightningd/invoice.h +++ b/lightningd/invoice.h @@ -31,7 +31,7 @@ struct invoice_details { u64 paid_timestamp; /* Set if state == PAID and invoice paid on chain; outpoint containing the payment */ const struct bitcoin_outpoint *paid_outpoint; - /* BOLT-11 or BOLT-12 encoding for this invoice */ + /* Either BOLT-11 or BOLT-12 encoding for this invoice */ const char *invstring; /* The description of the payment. */ diff --git a/openingd/dualopend.c b/openingd/dualopend.c index e1940a44e516..f8eb9eeffa0b 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -2338,7 +2338,7 @@ static void accept_tlv_add_offer(struct tlv_accept_tlvs *a_tlv, "Bad sign_option_will_fund_offer_reply %s", tal_hex(tmpctx, msg)); - /* BOLT- #2: + /* BOLT-liquidity-ads #2: * The accepting node: * ... * - MUST set `funding_fee_base_sat` to the base fee @@ -2562,7 +2562,7 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) } } - /* BOLT- #2: + /* BOLT-liquidity-ads #2: * * - if they decide to accept the offer: * ... @@ -2584,7 +2584,7 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) tx_state->lease_expiry = tx_state->blockheight + LEASE_RATE_DURATION; - /* BOLT- #2: + /* BOLT-liquidity-ads #2: * The lease fee is added to the accepter's balance * in a channel, in addition to the `funding_satoshi` * that they are contributing. The channel initiator @@ -2685,7 +2685,7 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) */ a_tlv->channel_type = state->channel_type->features; - /* BOLT- #2: + /* BOLT-liquidity-ads #2: * The accepting node: * ... * - if the `option_will_fund` tlv was sent in `open_channel2`: @@ -3175,7 +3175,7 @@ static void opener_start(struct state *state, u8 *msg) return; } - /* BOLT- #2: + /* BOLT-liquidity-ads #2: * The accepting node: ... * - if they decide to accept the offer: * - MUST include a `will_fund` tlv @@ -3218,7 +3218,7 @@ static void opener_start(struct state *state, u8 *msg) return; } - /* BOLT- #2: + /* BOLT-liquidity-ads #2: * The lease fee is added to the accepter's balance * in a channel, in addition to the `funding_satoshi` * that they are contributing. The channel initiator diff --git a/plugins/funder.c b/plugins/funder.c index 6ce91b6959de..04883723a188 100644 --- a/plugins/funder.c +++ b/plugins/funder.c @@ -872,7 +872,7 @@ json_openchannel2_call(struct command *cmd, if (!amount_sat_is_zero(info->requested_lease)) { u32 upper_bound, lower_bound; - /* BOLT- #2: + /* BOLT-liquidity-ads #2: * The receiving node: * - MAY fail the negotiation if: ... * - if the `option_will_fund` tlv is present and: diff --git a/plugins/test/run-decode_guess_type.c b/plugins/test/run-decode_guess_type.c index 038f3124f440..89fa01cacfe0 100644 --- a/plugins/test/run-decode_guess_type.c +++ b/plugins/test/run-decode_guess_type.c @@ -247,7 +247,7 @@ int main(int argc, char *argv[]) common_setup(argv[0]); static const struct likely_test tests[] = { - /* BOLT-12 */ + /* From BOLT-12: */ { "lno1qqqqqq", LIKELY_BOLT12_OFFER }, { "LNO1QQQQQQ", LIKELY_BOLT12_OFFER }, { "lni1abcd", LIKELY_BOLT12_INV }, @@ -261,7 +261,7 @@ int main(int argc, char *argv[]) { "clnemerg1foo", LIKELY_EMERGENCY_RECOVER }, { "CLNEMERG1FOO", LIKELY_EMERGENCY_RECOVER }, - /* BOLT-11 (lower + upper, amount + no amount) */ + /* From BOLT-11: (lower + upper, amount + no amount) */ { "lnbc1qqqqqq", LIKELY_BOLT11 }, { "LNBC1QQQQQQ", LIKELY_BOLT11 }, { "lnbc10u1qqqqqq", LIKELY_BOLT11 }, diff --git a/plugins/xpay/xpay.c b/plugins/xpay/xpay.c index d9a3c297ff8b..99e13b6cc138 100644 --- a/plugins/xpay/xpay.c +++ b/plugins/xpay/xpay.c @@ -104,9 +104,9 @@ struct payment { u32 maxdelay; /* If non-zero: maximum number of payment routes that can be pending. */ u32 maxparts; - /* BOLT-11 payment secret (NULL for BOLT-12, it uses blinded paths) */ + /* Payment secret for BOLT-11 (NULL for BOLT-12, it uses blinded paths) */ const struct secret *payment_secret; - /* BOLT-11 payment metadata (NULL for BOLT-12, it uses blinded paths) */ + /* Payment metadata for BOLT-11 (NULL for BOLT-12, it uses blinded paths) */ const u8 *payment_metadata; /* Final CLTV value */ u32 final_cltv; diff --git a/pyproject.toml b/pyproject.toml index d9470b57b072..3ad33b7591f5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,7 @@ dependencies = [ # We want a specific version of protobuf to match CI's .github/scripts/setup.sh "protobuf==6.32.1", "cryptography>=46", + "greatspectations>=0.2.3", "pyln-client", "pyln-proto", "pyln-grpc-proto", diff --git a/tests/test_opening.py b/tests/test_opening.py index 82f2e6baf631..0561616e9888 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -2081,7 +2081,7 @@ def test_scid_alias_private(node_factory, bitcoind): assert err.value.error['data']['erring_node'] == l2.info['id'] assert err.value.error['data']['erring_channel'] == scid23 - # BOLT #2 + # BOLT #2: # - MUST always recognize the `alias` as a `short_channel_id` for incoming HTLCs to this channel. route[1]['channel'] = alias23 l1.rpc.sendpay(route, inv['payment_hash'], payment_secret=inv['payment_secret']) diff --git a/tests/test_renepay.py b/tests/test_renepay.py index 52d4b951ac47..0cff10131432 100644 --- a/tests/test_renepay.py +++ b/tests/test_renepay.py @@ -863,13 +863,13 @@ def test_offer_selfpay(node_factory): def test_unannounced(node_factory): l1, l2 = node_factory.line_graph(2, announce_channels=False, opts={'allow-deprecated-apis': True}) - # BOLT-11 direct peer + # Direct peer: BOLT-11 b11 = l2.rpc.invoice( "100sat", "test_renepay_unannounced", "test_renepay_unannounced" )["bolt11"] ret = l1.rpc.call("renepay", {"invstring": b11}) assert ret["status"] == "complete" - # BOLT-12 direct peer + # Direct peer: BOLT-12 offer = l2.rpc.offer("any")["bolt12"] b12 = l1.rpc.fetchinvoice(offer, "21sat")["invoice"] ret = l1.rpc.call("renepay", {"invstring": b12}) @@ -889,7 +889,7 @@ def test_cltv_value(node_factory, bitcoind): }, ) blockheight = l1.rpc.waitblockheight(0)["blockheight"] - # BOLT-11 direct peer + # Direct peer, BOLT-11 b11 = l3.rpc.invoice( "100sat", "test_renepay_expiry_too_far", "test_renepay_expiry_too_far" )["bolt11"] diff --git a/tests/test_xpay.py b/tests/test_xpay.py index 4c4cec3f848a..dd222cb9b505 100644 --- a/tests/test_xpay.py +++ b/tests/test_xpay.py @@ -147,7 +147,7 @@ def test_xpay_simple(node_factory): node_factory.join_nodes([l1, l2, l3], wait_for_announce=True) node_factory.join_nodes([l3, l4], announce_channels=False) - # BOLT-11, direct peer + # Direct peer, BOLT-11 b11 = l2.rpc.invoice('10000msat', 'test_xpay_simple', 'test_xpay_simple bolt11')['bolt11'] ret = l1.rpc.xpay(b11) assert ret['failed_parts'] == 0 @@ -162,7 +162,7 @@ def test_xpay_simple(node_factory): l1.rpc.xpay(b11_paid) assert err.value.error['code'] == PAY_INJECTPAYMENTONION_ALREADY_PAID - # BOLT-11, indirect peer + # Indirect peer, BOLT-11 b11 = l3.rpc.invoice('10000msat', 'test_xpay_simple', 'test_xpay_simple bolt11')['bolt11'] ret = l1.rpc.xpay(b11) assert ret['failed_parts'] == 0 @@ -170,16 +170,16 @@ def test_xpay_simple(node_factory): assert ret['amount_msat'] == 10000 assert ret['amount_sent_msat'] == 10001 - # BOLT-11, routehint + # Routehint, BOLT-11 b11 = l4.rpc.invoice('10000msat', 'test_xpay_simple', 'test_xpay_simple bolt11')['bolt11'] l1.rpc.xpay(b11) - # BOLT-12 (with payer_note specified). + # payer_note in BOLT-12 offer = l3.rpc.offer('any')['bolt12'] b12 = l1.rpc.fetchinvoice(offer, '100000msat')['invoice'] l1.rpc.xpay(invstring=b12, payer_note="Payment for a cup of coffee") - # BOLT-12, direct peer + # Direct peer, BOLT-12 offer = l2.rpc.offer('any')['bolt12'] b12 = l1.rpc.fetchinvoice(offer, '10000msat')['invoice'] ret = l1.rpc.xpay(invstring=b12) @@ -428,7 +428,7 @@ def test_xpay_takeover(node_factory, executor): l1.rpc.pay(b12) l1.daemon.wait_for_log('Redirecting pay->xpay') - # BOLT-11 with amount. + # Amount-included, BOLT-11. inv = l3.rpc.invoice('any', "test_xpay_takeover3", "test_xpay_takeover3")['bolt11'] l1.rpc.pay(inv, amount_msat=10000) l1.daemon.wait_for_log('Redirecting pay->xpay') @@ -570,7 +570,7 @@ def test_xpay_maxdelay(node_factory): def test_xpay_unannounced(node_factory): l1, l2 = node_factory.line_graph(2, announce_channels=False) - # BOLT-11, direct peer + # Direct peer, BOLT-11. b11 = l2.rpc.invoice('10000msat', 'test_xpay_unannounced', 'test_xpay_unannounced bolt11')['bolt11'] ret = l1.rpc.xpay(b11) assert ret['failed_parts'] == 0 @@ -578,7 +578,7 @@ def test_xpay_unannounced(node_factory): assert ret['amount_msat'] == 10000 assert ret['amount_sent_msat'] == 10000 - # BOLT-12, direct peer + # Direct peer, BOLT-12 offer = l2.rpc.offer('any')['bolt12'] b12 = l1.rpc.fetchinvoice(offer, '100000msat')['invoice'] l1.rpc.xpay(b12) @@ -597,7 +597,7 @@ def test_xpay_zeroconf(node_factory): wait_for(lambda: all([c['state'] == 'CHANNELD_NORMAL' for c in l1.rpc.listpeerchannels()['channels'] + l2.rpc.listpeerchannels()['channels']])) - # BOLT-11, direct peer + # Direct peer, BOLT-11 b11 = l2.rpc.invoice('10000msat', 'test_xpay_unannounced', 'test_xpay_unannounced bolt11')['bolt11'] ret = l1.rpc.xpay(b11) assert ret['failed_parts'] == 0 @@ -605,7 +605,7 @@ def test_xpay_zeroconf(node_factory): assert ret['amount_msat'] == 10000 assert ret['amount_sent_msat'] == 10000 - # BOLT-12, direct peer + # Direct peer, BOLT-12 offer = l2.rpc.offer('any')['bolt12'] b12 = l1.rpc.fetchinvoice(offer, '100000msat')['invoice'] l1.rpc.xpay(b12) diff --git a/uv.lock b/uv.lock index f764e3e3e1b7..82922d9580fc 100644 --- a/uv.lock +++ b/uv.lock @@ -401,6 +401,7 @@ version = "0.1.0" source = { virtual = "." } dependencies = [ { name = "cryptography" }, + { name = "greatspectations" }, { name = "grpcio" }, { name = "grpcio-tools" }, { name = "mako" }, @@ -439,6 +440,7 @@ dev = [ [package.metadata] requires-dist = [ { name = "cryptography", specifier = ">=46" }, + { name = "greatspectations", specifier = ">=0.2.3" }, { name = "grpcio", specifier = "==1.75.1" }, { name = "grpcio-tools", specifier = "==1.75.1" }, { name = "mako", specifier = ">=1.1.6" }, @@ -687,7 +689,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -760,6 +762,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/08/98/2a46f4a3117c17fd36e07ad8b085054451e96723baaeea245682156ba546/flask_socketio-5.6.1-py3-none-any.whl", hash = "sha256:51a3f71b28b4476c650829607e3a993e076034db6c3cc31f718f0a4b45939d42", size = 18683, upload-time = "2026-02-21T13:07:51.442Z" }, ] +[[package]] +name = "greatspectations" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5f/3c/25700b4de2c63826cef9c1864d116b028d8984dafc3dabc8c08285530329/greatspectations-0.2.3.tar.gz", hash = "sha256:ad15b2cde353adfbe9e159c83e724cf6584c62fc18d5b4eddbd5f906d84c5cd4", size = 47084, upload-time = "2026-07-30T05:48:57.248Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/ac/4d2e30b0d3d456775a23e6b7cd1e229e34fd5e6ec0c047edf6fb24fad479/greatspectations-0.2.3-py3-none-any.whl", hash = "sha256:c49a32959fec1032729352a5d851977cbbe5cd90791479c5c844de5e59835313", size = 32618, upload-time = "2026-07-30T05:48:55.812Z" }, +] + [[package]] name = "grpcio" version = "1.75.1" diff --git a/wire/peer_wire.c b/wire/peer_wire.c index 2357073491a1..36af71699d1c 100644 --- a/wire/peer_wire.c +++ b/wire/peer_wire.c @@ -397,7 +397,7 @@ bool extract_channel_id(const u8 *in_pkt, struct channel_id *channel_id) * * [`channel_id`:`channel_id`] */ case WIRE_SPLICE_INIT: - /* BOLT-splice #2: + /* BOLT #2: * 1. type: 80 (`splice_init`) * 2. data: * * [`channel_id`:`channel_id`] @@ -407,7 +407,7 @@ bool extract_channel_id(const u8 *in_pkt, struct channel_id *channel_id) * * [`point`:`funding_pubkey`] */ case WIRE_SPLICE_ACK: - /* BOLT-splice #2: + /* BOLT #2: * 1. type: 81 (`splice_ack`) * 2. data: * * [`channel_id`:`channel_id`] @@ -415,7 +415,7 @@ bool extract_channel_id(const u8 *in_pkt, struct channel_id *channel_id) * * [`point`:`funding_pubkey`] */ case WIRE_SPLICE_LOCKED: - /* BOLT-splice #2: + /* BOLT #2: * 1. type: 77 (`splice_locked`) * 2. data: * * [`channel_id`:`channel_id`] diff --git a/wire/test/run-tlvstream.c b/wire/test/run-tlvstream.c index 5aa609336299..7b38673cbd2b 100644 --- a/wire/test/run-tlvstream.c +++ b/wire/test/run-tlvstream.c @@ -42,7 +42,7 @@ void towire_channel_id(u8 **pptr UNNEEDED, const struct channel_id *channel_id U /* AUTOGENERATED MOCKS END */ -/* BOLT #1 +/* BOLT #1: ### TLV Decoding Failures The following TLV streams in any namespace should trigger a decoding failure: