Skip to content

Commit bbdbd6f

Browse files
authored
Merge pull request #3706 from TheBlueMatt/2024-12-0.1-bindings
[0.1-bindings] Update bindings to 0.1.2 and include `lightning-liquidity`
2 parents 54a945b + 0f5a0fd commit bbdbd6f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+2018
-1430
lines changed

.github/workflows/semver.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: SemVer checks
2+
on:
3+
push:
4+
branches-ignore:
5+
- master
6+
pull_request:
7+
branches-ignore:
8+
- master
9+
10+
jobs:
11+
semver-checks:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Checkout source code
15+
uses: actions/checkout@v4
16+
- name: Install Rust stable toolchain
17+
run: |
18+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal --default-toolchain stable
19+
rustup override set stable
20+
- name: Check SemVer with default features
21+
uses: obi1kenobi/cargo-semver-checks-action@v2
22+
with:
23+
feature-group: default-features
24+
- name: Check SemVer *without* default features
25+
uses: obi1kenobi/cargo-semver-checks-action@v2
26+
with:
27+
feature-group: only-explicit-features
28+
- name: Check lightning-background-processor SemVer
29+
uses: obi1kenobi/cargo-semver-checks-action@v2
30+
with:
31+
package: lightning-background-processor
32+
feature-group: only-explicit-features
33+
features: futures
34+
- name: Check lightning-block-sync SemVer
35+
uses: obi1kenobi/cargo-semver-checks-action@v2
36+
with:
37+
package: lightning-block-sync
38+
feature-group: only-explicit-features
39+
features: rpc-client,rest-client
40+
- name: Check lightning-transaction-sync electrum SemVer
41+
uses: obi1kenobi/cargo-semver-checks-action@v2
42+
with:
43+
manifest-path: lightning-transaction-sync/Cargo.toml
44+
feature-group: only-explicit-features
45+
features: electrum
46+
- name: Check lightning-transaction-sync esplora-blocking SemVer
47+
uses: obi1kenobi/cargo-semver-checks-action@v2
48+
with:
49+
manifest-path: lightning-transaction-sync/Cargo.toml
50+
feature-group: only-explicit-features
51+
features: esplora-blocking
52+
- name: Check lightning-transaction-sync esplora-async SemVer
53+
uses: obi1kenobi/cargo-semver-checks-action@v2
54+
with:
55+
manifest-path: lightning-transaction-sync/Cargo.toml
56+
feature-group: only-explicit-features
57+
features: esplora-async

CHANGELOG.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,40 @@
1+
# 0.1.2 - Apr 02, 2025 - "Foolishly Edgy Cases"
2+
3+
## API Updates
4+
* `lightning-invoice` is now re-exported as `lightning::bolt11_invoice`
5+
(#3671).
6+
7+
## Performance Improvements
8+
* `rapid-gossip-sync` graph parsing is substantially faster, resolving a
9+
regression in 0.1 (#3581).
10+
* `NetworkGraph` loading is now substantially faster and does fewer
11+
allocations, resulting in a 20% further improvement in `rapid-gossip-sync`
12+
loading when initializing from scratch (#3581).
13+
* `ChannelMonitor`s for closed channels are no longer always re-persisted
14+
immediately after startup, reducing on-startup I/O burden (#3619).
15+
16+
## Bug Fixes
17+
* BOLT 11 invoices longer than 1023 bytes long (and up to 7089 bytes) now
18+
properly parse (#3665).
19+
* In some cases, when using synchronous persistence with higher latency than
20+
the latency to communicate with peers, when receiving an MPP payment with
21+
multiple parts received over the same channel, a channel could hang and not
22+
make progress, eventually leading to a force-closure due to timed-out HTLCs.
23+
This has now been fixed (#3680).
24+
* Some rare cases with multi-hop BOLT 11 route hints or multiple redundant
25+
blinded paths could have led to the router creating invalid `Route`s were
26+
fixed (#3586).
27+
* Corrected the decay logic in `ProbabilisticScorer`'s historical buckets
28+
model. Note that by default historical buckets are only decayed if no new
29+
datapoints have been added for a channel for two weeks (#3562).
30+
* `{Channel,Onion}MessageHandler::peer_disconnected` will now be called if a
31+
different message handler refused connection by returning an `Err` from its
32+
`peer_connected` method (#3580).
33+
* If the counterparty broadcasts a revoked state with pending HTLCs, those
34+
will now be claimed with other outputs which we consider to not be
35+
vulnerable to pinning attacks if they are not yet claimable by our
36+
counterparty, potentially reducing our exposure to pinning attacks (#3564).
37+
138
# 0.1.1 - Jan 28, 2025 - "Onchain Matters"
239

340
## API Updates

ci/ci-tests.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,5 @@ RUSTFLAGS="--cfg=taproot" cargo test --verbose --color always -p lightning
132132
RUSTFLAGS="--cfg=splicing" cargo test --verbose --color always -p lightning
133133
[ "$CI_MINIMIZE_DISK_USAGE" != "" ] && cargo clean
134134
RUSTFLAGS="--cfg=async_payments" cargo test --verbose --color always -p lightning
135+
[ "$CI_MINIMIZE_DISK_USAGE" != "" ] && cargo clean
136+
RUSTFLAGS="--cfg=lsps1_service" cargo test --verbose --color always -p lightning-liquidity

lightning-background-processor/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2371,8 +2371,8 @@ mod tests {
23712371
42,
23722372
53,
23732373
features,
2374-
$nodes[0].node.get_our_node_id(),
2375-
$nodes[1].node.get_our_node_id(),
2374+
$nodes[0].node.get_our_node_id().into(),
2375+
$nodes[1].node.get_our_node_id().into(),
23762376
)
23772377
.expect("Failed to update channel from partial announcement");
23782378
let original_graph_description = $nodes[0].network_graph.to_string();

lightning-invoice/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "lightning-invoice"
33
description = "Data structures to parse and serialize BOLT11 lightning invoices"
4-
version = "0.33.1"
4+
version = "0.33.2"
55
authors = ["Sebastian Geisler <[email protected]>"]
66
documentation = "https://docs.rs/lightning-invoice/"
77
license = "MIT OR Apache-2.0"

lightning-invoice/src/de.rs

Lines changed: 243 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ use core::str::FromStr;
99
use std::error;
1010

1111
use bech32::primitives::decode::{CheckedHrpstring, CheckedHrpstringError};
12-
use bech32::{Bech32, Fe32, Fe32IterExt};
12+
use bech32::{Fe32, Fe32IterExt};
1313

1414
use crate::prelude::*;
15+
use crate::Bolt11Bech32;
1516
use bitcoin::hashes::sha256;
1617
use bitcoin::hashes::Hash;
1718
use bitcoin::{PubkeyHash, ScriptHash, WitnessVersion};
@@ -377,7 +378,7 @@ impl FromStr for SignedRawBolt11Invoice {
377378
type Err = Bolt11ParseError;
378379

379380
fn from_str(s: &str) -> Result<Self, Self::Err> {
380-
let parsed = CheckedHrpstring::new::<Bech32>(s)?;
381+
let parsed = CheckedHrpstring::new::<Bolt11Bech32>(s)?;
381382
let hrp = parsed.hrp();
382383
// Access original non-packed 32 byte values (as Fe32s)
383384
// Note: the type argument is needed due to the API peculiarities, but it's not used
@@ -1175,4 +1176,244 @@ mod test {
11751176
)
11761177
)
11771178
}
1179+
1180+
// Test some long invoice test vectors successfully roundtrip. Generated
1181+
// from Lexe proptest: <https://github.com/lexe-app/lexe-public/blob/4bc7018307e5221e1e1ee8b17ce366338fb11a16/common/src/ln/invoice.rs#L183>.
1182+
#[test]
1183+
fn test_deser_long_test_vectors() {
1184+
use crate::Bolt11Invoice;
1185+
1186+
#[track_caller]
1187+
fn parse_ok(invoice_str: &str) {
1188+
let invoice = Bolt11Invoice::from_str(invoice_str).unwrap();
1189+
let invoice_str2 = invoice.to_string();
1190+
if invoice_str != invoice_str2 {
1191+
panic!(
1192+
"Invoice does not roundtrip: invoice_str != invoice_str2\n\
1193+
invoice_str: {invoice_str}\n\
1194+
invoice_str2: {invoice_str2}\n\
1195+
\n\
1196+
{invoice:?}"
1197+
);
1198+
}
1199+
}
1200+
1201+
// 1024 B shrunk invoice just above previous limit of 1023 B from Lexe proptest
1202+
parse_ok(
1203+
"lnbc10000000000000000010p1qqqqqqqdtuxpqkzq8sjzqgps4pvyczqq8sjzqgpuysszq0pyyqsrp2zs0sjz\
1204+
qgps4pxrcfpqyqc2slpyyqsqsv9gwz59s5zqpqyps5rc9qsrs2pqxz5ysyzcfqgysyzs0sjzqgqq8sjzqgps4p\
1205+
xqqzps4pqpssqgzpxps5ruysszqrps4pg8p2zgpsc2snpuysszqzqsgqvys0pyyqsrcfpqyqvycv9gfqqrcfpq\
1206+
yq7zggpq8q5zqyruysszqwpgyqxpsjqsgq7zggpqps7zggpq8sjzqgqgqq7zggpqpq7zggpq8q5zqqpuysszq0\
1207+
pyyqsqs0pyyqspsnqgzpqpqlpyyqsqszpuysszqyzvzpvysrqq8sjzqgqvrp7zggpqpqxpsspp5mf45hs3cgph\
1208+
h0074r5qmr74y82r26ac4pzdg4nd9mdmsvz6ffqpssp5vr4yra4pcv74h9hk3d0233nqu4gktpuykjamrafrdp\
1209+
uedqugzh3q9q2sqqqqqysgqcqrpqqxq8pqqqqqqnp4qgvcxpme2q5lng36j9gruwlrtk2f86s3c5xmk87yhvyu\
1210+
wdeh025q5r9yqwnqegv9hj9nzkhyxaeyq92wcrnqp36pyrc2qzrvswj5g96ey2dn6qqqqqqqqqqqqqqqqqqqqq\
1211+
qqqqqqqqp9a5vs0t4z56p64xyma8s84yvdx7uhqj0gvrr424fea2wpztq2fwqqqqqqqqqqqqqqqqqqqqqqqqqq\
1212+
qqqqmy9qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\
1213+
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpcnsxc32du9n7amlypuhclzqrt6lkegq\
1214+
0v3r7nczjv9tv30z7phq80r3dm7pvgykl7gwuenmem93h5xwdwac6ngsmzqc34khrg3qjgsq6qk6lc"
1215+
);
1216+
// 1517 B mainnet invoice from Lexe proptest
1217+
parse_ok(
1218+
"lnbc8735500635020489010p1av5kfs8deupvyk4u5ynj03hmalhhhml0fxc2jlrv9z4lg6s4hnhkz69malhhe\
1219+
t3x9yqpsxru4a3kwar2qtu2q2ughx367q600s5x7c7tln4k0fu78skxqevaqm8sayhuur377zgf3uf94n57xzh\
1220+
dw99u42hwc089djn5xj723w7zageflsnzdmyte89tecf2ac7xhg4y3u9f4xpuv2hwxjlsarp0e24fu8tme6rgv\
1221+
0tqj08z9f4u30rw59k8emhtvs7wye0xfw6x5q5tju2p208rvtkunzwtwghtp22tlnh62gxwhfkxp4cnz7ts3rx\
1222+
vlzszhv9y00h77lpdvcjyhjtmalh5dn5e8n5w8cqle0vunzduu4nza9y0734qhxday9hzywl0aa0vhzy0qmphc\
1223+
64d4hduj08dv2krpgqtc2v83gptk34reelxyc7wsgnze890c6nrv6p0cmepatc269eayzjjkqk30n52rfl5dg7\
1224+
wztl96f7wc2tzx34q909xuajnyt4u4lnk87lwal7z0etdz5tmece0v3u796jfp68nccn05ty54ncfelts3v8g0\
1225+
sn6v6hsu87zat4r03368ersu87252dd0nswymxzc2pyxl8yy844hspuyj47w0px4u4leefq568sk0rr9th4ql9\
1226+
f9ykawrczkz5hp22nstg3lrlsa6u2q2ull3kzce2sh0h77sjv0zszhzy4hfh6u0pwux5l3gpthsn72mfu47sw9\
1227+
zw3hzk7srznp27z0etdp0725me00sn72mgkf0fteehruk0lg6swh34z52puaekzmjlmalhhe6m8ug7z3c8g8zh\
1228+
jjspp5zj0sm85g5ufng9w7s6p4ucdk80tyvz64sg54v0cy4vgnr37f78sqsp5l6azu2hv6we30er90jrslqpvd\
1229+
trnrphhesca2wg5q83k52rsu2cq9q2sqqqqqysgqcqr8h2np4qw0ha2k282hm8jh5rcfq0hsp2zhddtlc5vs23\
1230+
uphyv0lv3k8sqsfgfp4qyrk86tx5xg2aa7et4cdzhnvl5s4nd33ugytt7gamk9tugn9yransr9yq08gpwsn8t2\
1231+
tq4ducjfhrcz707av0ss20urjh8vldrpmehqxa0stkesvuq82txyqzfhej7qccswy7k5wvcppk63c6zpjytfda\
1232+
ccadacjtn52lpe6s85rjfqlxzp6frq33xshaz2nr9xjkhd3jj8qg39nmfzvpgmayakqmy9rseakwgcudug7hs4\
1233+
5wh430ywh7qhj3khczh8gle4cn93ymgfwa7rrvcw9lywyyz58k4p40a3nu9svthaf0qeg8f2ay4tw9p48p70qm\
1234+
ayu3ejl2q8pj9e2l22h7775tl44hs6ke4sdfgcr6aj8wra4r2v9sj6xa5chd5ctpfg8chtrer3kkp0e6af88lk\
1235+
rfxcklf2hyslv2hr0xl5lwrm5y5uttxn4ndfz8789znf78nspa3xy68"
1236+
);
1237+
// 1804 B regtest invoice from Lexe proptest
1238+
parse_ok(
1239+
"lnbcrt17124979001314909880p1y6lkcwgd76tfnxksfk2atyy4tzw4nyg6jrx3282s2ygvcxyj64gevhxsjk\
1240+
2ymhzv3e0p5h5u3kfey92jt9ge44gsfnwycxynm2g3unw3ntt9qh25texe98jcfhxvcxuezxw9tngwrndpy9s4\
1241+
p4x9eyze2tfe9rxm68tp5yj5jfduen2nny8prhsm6edegn2stww4n4gwp4vfjkvdthd43524n9fa8h262vwesk\
1242+
g66nw3vnyafn29zhsvfeg9mxummtfp35uumzfqmhy3jwgdh55mt5xpvhgmjn25uku5e5g939wmmnvdfygnrdgd\
1243+
h56uzcx4a92vfhgdcky3z9gfnrsvp4f4f55j68vak9yufhvdm8x5zrgc6955jvf429zumv89nh2a35wae5yntg\
1244+
v985jumpxehyv7t92pjrwufs89yh23f5ddy5s568wgchve3cg9ek5nzewgcrzjz0dftxg3nvf4hngje52ac4zm\
1245+
esxpvk6sfef4hkuetvd4vk6n29wftrw5rvg4yy2vjjwyexc5mnvfd8xknndpqkkenx0q642j35298hwve3dyc5\
1246+
25jrd3295sm9v9jrqup3wpykg7zd239ns7jgtqu95jz0deaxksjh2fu56n6n2f5x6mm8wa89qjfef385sam2x9\
1247+
mxcs20gfpnq460d3axzknnf3e4sw2kvf25wjjxddpyg52dw4vx7nn2w9cyu5t8vfnyxjtpg33kssjp24ch536p\
1248+
d938snmtx345x6r4x93kvv2tff855um3tfekxjted4kxys2kve5hvu6g89z4ynmjgfhnw7tv892rymejgvey77\
1249+
rcfqe9xjr92d85636fvajxyajndfa92k2nxycx5jtjx4zxsm2y2dyn2up50f5ku3nrfdk4g5npxehkzjjv8y69\
1250+
gveev4z56denddaxy7tfwe8xx42zgf6kzmnxxpk826ze2s6xk6jrwearw6ejvd8rsvj2fpg525jtd5pp5j2tlt\
1251+
28m4kakjr84w6ce4fd8e7awy6ncyswcyut760rdnem30ptssp5p5u3xgxxtr6aev8y2w9m30wcw3kyn7fgm8wm\
1252+
f8qw8wzrqt34zcvq9q2sqqqqqysgqcqypmw9xq8lllllllnp4qt36twam2ca08m3s7vnhre3c0j89589wyw4vd\
1253+
k7fln0lryxzkdcrur28qwqq3hnyt84vsasuldd2786eysdf4dyuggwsmvw2atftf7spkmpa9dd3efq5tenpqm2\
1254+
v7vcz2a4s0s7jnqpjn0srysnstnw5y5z9taxn0ue37aqgufxcdsj6f8a2m4pm9udppdzc4shsdqzzx0u0rm4xl\
1255+
js0dqz3c5zqyvglda7nsqvqfztmlyup7vyuadzav4zyuqwx90ev6nmk53nkhkt0sev9e745wxqtdvrqzgqkaka\
1256+
zen7e2qmsdauk665g3llg5qtl79t3xulrhjnducehdn72gpmkjvtth7kh6ejpl9dv0qcsxv2jvzzvg0hzdmk3y\
1257+
jsmydqksdk3h78kc63qnr265h8vyeslqexszppfm7y287t3gxvhw0ulg2wp0rsw3tevz03z50kpy77zdz9snxm\
1258+
kkwxd76xvj4qvj2f89rrnuvdvzw947ay0kydc077pkec2jet9qwp2tud98s24u65uz07eaxk5jk3e4nggn2caa\
1259+
ek2p5pkrc6mm6mxjm2ezpdu8p5jstg6tgvnttgac3ygt5ys04t4udujzlshpl7e4f3ff03xe6v24cp6aq4wa"
1260+
);
1261+
// 1870 B testnet invoice from Lexe proptest
1262+
parse_ok(
1263+
"lntb5826417333454665580p1c5rwh5edlhf33hvkj5vav5z3t02a5hxvj3vfv5kuny2f3yzj6zwf9hx3nn2fk\
1264+
9gepc2a3ywvj6dax5v3jy2d5nxmp3gaxhycjkv38hx4z4d4vyznrp2p24xa6t2pg4w4rrxfens6tcxdhxvvfhx\
1265+
a8xvvpkgat8xnpe2p44juz9g43hyur00989gvfhwd2kj72wfum4g4mgx5m5cs2rg9d9vnn6xe89ydnnvfpyy52\
1266+
s2dxx2er4x4xxwstdd5cxwdrjw3nkxnnv2uexxnrxw4t56sjswfn52s2xv4t8xmjtwpn8xm6sfeh4q526dyu8x\
1267+
3r9gceyw6fhd934qjttvdk57az5w368zdrhwfjxxu35xcmrsmmpd4g8wwtev4tkzutdd32k56mxveuy6c6v2em\
1268+
yv7zkfp39zjpjgd8hx7n4xph5kceswf6xxmnyfcuxca20fp24z7ncvfhyu5jf2exhw36nwf68s7rh2a6yzjf4d\
1269+
gukcenfxpchqsjn2pt5x334tf98wsm6dvcrvvfcwapxvk2cdvmk2npcfe68zue3w4f9xc6s2fvrw6nrg3fkskt\
1270+
e2ftxyc20ffckcd692964sdzjwdp4yvrfdfm9q72pxp3kwat5f4j9xee5da8rss60w92857tgwych55f5w3n8z\
1271+
mzexpy4jwredejrqm6txf3nxm64ffh8x460dp9yjazhw4yx6dm5xerysnn5wa455k3h2d89ss2fd9axwjp3f4r\
1272+
9qdmfd4fx6stx2eg9sezrv369w7nvvfvhj4nnwaz5z3ny8qcxcdnvwd64jc2nx9uy2e2gxdrnx6r3w9ykxatxx\
1273+
g6kk6rv2ekr2emwx5ehy362d3x82dzvddfxs5rcg4vn27npf564qdtg2anycc6523jnwe3e0p65unrpvccrs5m\
1274+
2fuexgmnj23ay5e34v4xk5jnrwpg4xemfwqe5vjjjw9qk76zsd9yrzu6xdpv5v5ntdejxg6jtv3kx65t6gdhrg\
1275+
vj3fe34sj2vv3h5kegpp57hjf5kv6clw97y2e063yuz0psrz9a6l49v836dflum00rh8qtn8qsp5gd29qycuze\
1276+
08xls8l32zjaaf2uqv78v97lg9ss0c699huw980h2q9q2sqqqqqysgqcqr8ulnp4q26hcfwr7qxz7lwwlr2kjc\
1277+
rws7m2u5j36mm0kxa45uxy6zvsqt2zzfppjdkrm2rlgadt9dq3d6jkv4r2cugmf2kamr28qwuleyzzyyly8a6t\
1278+
u70eldahx7hzxx5x9gms7vjjr577ps8n4qyds5nern39j0v7czkch2letnt46895jupxgehf208xgxz8d6j8gu\
1279+
3h2qqtsk9nr9nuquhkqjxw40h2ucpldrawmktxzxdgtkt9a3p95g98nywved8s8laj2a0c98rq5zzdnzddz6nd\
1280+
w0lvr6u0av9m7859844cgz9vpeq05gw79zqae2s7jzeq66wydyueqtp56qc67g7krv6lj5aahxtmq4y208q5qy\
1281+
z38cnwl9ma6m5f4nhzqaj0tjxpfrk4nr5arv9d20lvxvddvffhzygmyuvwd959uhdcgcgjejchqt2qncuwpqqk\
1282+
5vws7dflw8x6esrfwhz7h3jwmhevf445k76nme926sr8drsdveqg7l7t7lnjvhaludqnwk4l2pmevkjf9pla92\
1283+
4p77v76r7x8jzyy7h59hmk0lgzfsk6c8dpj37hssj7jt4q7jzvy8hq25l3pag37axxanjqnq56c47gpgy6frsy\
1284+
c0str9w2aahz4h6t7axaka4cwvhwg49r6qgj8kwz2mt6vcje25l9ekvmgq5spqtn"
1285+
);
1286+
}
1287+
1288+
// Generate a valid invoice of `MAX_LENGTH` bytes and ensure that it roundtrips.
1289+
#[test]
1290+
fn test_serde_long_invoice() {
1291+
use crate::TaggedField::*;
1292+
use crate::{
1293+
Bolt11Invoice, Bolt11InvoiceFeatures, Bolt11InvoiceSignature, Currency,
1294+
PositiveTimestamp, RawBolt11Invoice, RawDataPart, RawHrp, RawTaggedField, Sha256,
1295+
SignedRawBolt11Invoice,
1296+
};
1297+
use bitcoin::secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
1298+
use bitcoin::secp256k1::PublicKey;
1299+
use lightning_types::routing::{RouteHint, RouteHintHop, RoutingFees};
1300+
1301+
// Generate an `UnknownSemantics` field with a given length.
1302+
fn unknown_semantics_field(len: usize) -> Vec<Fe32> {
1303+
assert!(len <= 1023);
1304+
let mut field = Vec::with_capacity(len + 3);
1305+
// Big-endian encoded length prefix
1306+
field.push(Fe32::Q);
1307+
field.push(Fe32::try_from((len >> 5) as u8).unwrap());
1308+
field.push(Fe32::try_from((len & 0x1f) as u8).unwrap());
1309+
// Data
1310+
field.extend(std::iter::repeat(Fe32::P).take(len));
1311+
field
1312+
}
1313+
1314+
// Invoice fields
1315+
let payment_hash = sha256::Hash::from_str(
1316+
"0001020304050607080900010203040506070809000102030405060708090102",
1317+
)
1318+
.unwrap();
1319+
let description = std::iter::repeat("A").take(639).collect::<String>();
1320+
let fallback_addr = crate::Fallback::SegWitProgram {
1321+
version: bitcoin::WitnessVersion::V0,
1322+
program: vec![0; 32],
1323+
};
1324+
let payee_pk = PublicKey::from_slice(&[
1325+
0x03, 0x24, 0x65, 0x3e, 0xac, 0x43, 0x44, 0x88, 0x00, 0x2c, 0xc0, 0x6b, 0xbf, 0xb7,
1326+
0xf1, 0x0f, 0xe1, 0x89, 0x91, 0xe3, 0x5f, 0x9f, 0xe4, 0x30, 0x2d, 0xbe, 0xa6, 0xd2,
1327+
0x35, 0x3d, 0xc0, 0xab, 0x1c,
1328+
])
1329+
.unwrap();
1330+
let route_hints = std::iter::repeat(RouteHintHop {
1331+
src_node_id: payee_pk,
1332+
short_channel_id: 0x0102030405060708,
1333+
fees: RoutingFees { base_msat: 1, proportional_millionths: 20 },
1334+
cltv_expiry_delta: 3,
1335+
htlc_minimum_msat: None,
1336+
htlc_maximum_msat: None,
1337+
})
1338+
.take(12)
1339+
.collect::<Vec<_>>();
1340+
1341+
// Build raw invoice
1342+
let raw_invoice = RawBolt11Invoice {
1343+
hrp: RawHrp {
1344+
currency: Currency::Bitcoin,
1345+
raw_amount: Some(10000000000000000010),
1346+
si_prefix: Some(crate::SiPrefix::Pico),
1347+
},
1348+
data: RawDataPart {
1349+
timestamp: PositiveTimestamp::from_unix_timestamp(1496314658).unwrap(),
1350+
tagged_fields: vec![
1351+
PaymentHash(Sha256(payment_hash)).into(),
1352+
Description(crate::Description::new(description).unwrap()).into(),
1353+
PayeePubKey(crate::PayeePubKey(payee_pk)).into(),
1354+
ExpiryTime(crate::ExpiryTime(std::time::Duration::from_secs(u64::MAX))).into(),
1355+
MinFinalCltvExpiryDelta(crate::MinFinalCltvExpiryDelta(u64::MAX)).into(),
1356+
Fallback(fallback_addr).into(),
1357+
PrivateRoute(crate::PrivateRoute(RouteHint(route_hints))).into(),
1358+
PaymentSecret(crate::PaymentSecret([17; 32])).into(),
1359+
PaymentMetadata(vec![0x69; 639]).into(),
1360+
Features(Bolt11InvoiceFeatures::from_le_bytes(vec![0xaa; 639])).into(),
1361+
// This invoice is 4458 B w/o unknown semantics fields.
1362+
// Need to add some non-standard fields to reach 7089 B limit.
1363+
RawTaggedField::UnknownSemantics(unknown_semantics_field(1023)),
1364+
RawTaggedField::UnknownSemantics(unknown_semantics_field(1023)),
1365+
RawTaggedField::UnknownSemantics(unknown_semantics_field(576)),
1366+
],
1367+
},
1368+
};
1369+
1370+
// Build signed invoice
1371+
let hash = [
1372+
0x75, 0x99, 0xe1, 0x51, 0x7f, 0xa1, 0x0e, 0xb5, 0xc0, 0x79, 0xb4, 0x6e, 0x8e, 0x62,
1373+
0x0c, 0x4f, 0xb0, 0x72, 0x71, 0xd2, 0x81, 0xa1, 0x92, 0x65, 0x9c, 0x90, 0x89, 0x69,
1374+
0xe1, 0xf3, 0xd6, 0x59,
1375+
];
1376+
let signature = &[
1377+
0x6c, 0xbe, 0xbe, 0xfe, 0xd3, 0xfb, 0x07, 0x68, 0xb5, 0x79, 0x98, 0x82, 0x29, 0xab,
1378+
0x0e, 0xcc, 0x8d, 0x3a, 0x81, 0xee, 0xee, 0x07, 0xb3, 0x5d, 0x64, 0xca, 0xb4, 0x12,
1379+
0x33, 0x99, 0x33, 0x2a, 0x31, 0xc2, 0x2c, 0x2b, 0x62, 0x96, 0x4e, 0x37, 0xd7, 0x96,
1380+
0x50, 0x5e, 0xdb, 0xe9, 0xa9, 0x5b, 0x0b, 0x3b, 0x87, 0x22, 0x89, 0xed, 0x95, 0xf1,
1381+
0xf1, 0xdf, 0x2d, 0xb6, 0xbd, 0xf5, 0x0a, 0x20,
1382+
];
1383+
let signature = Bolt11InvoiceSignature(
1384+
RecoverableSignature::from_compact(signature, RecoveryId::from_i32(1).unwrap())
1385+
.unwrap(),
1386+
);
1387+
let signed_invoice = SignedRawBolt11Invoice { raw_invoice, hash, signature };
1388+
1389+
// Ensure serialized invoice roundtrips
1390+
let invoice = Bolt11Invoice::from_signed(signed_invoice).unwrap();
1391+
let invoice_str = invoice.to_string();
1392+
assert_eq!(invoice_str.len(), crate::MAX_LENGTH);
1393+
assert_eq!(invoice, Bolt11Invoice::from_str(&invoice_str).unwrap());
1394+
}
1395+
1396+
// Test that invoices above the maximum length fail to parse with the expected error.
1397+
#[test]
1398+
fn test_deser_too_long_fails() {
1399+
use crate::{Bolt11Invoice, ParseOrSemanticError, MAX_LENGTH};
1400+
use bech32::primitives::decode::{CheckedHrpstringError, ChecksumError};
1401+
1402+
fn parse_is_code_length_err(s: &str) -> bool {
1403+
// Need matches! b/c ChecksumError::CodeLength(_) is marked non-exhaustive
1404+
matches!(
1405+
Bolt11Invoice::from_str(s),
1406+
Err(ParseOrSemanticError::ParseError(Bolt11ParseError::Bech32Error(
1407+
CheckedHrpstringError::Checksum(ChecksumError::CodeLength(_))
1408+
))),
1409+
)
1410+
}
1411+
1412+
let mut too_long = String::from("lnbc1");
1413+
too_long.push_str(
1414+
String::from_utf8(vec![b'x'; (MAX_LENGTH + 1) - too_long.len()]).unwrap().as_str(),
1415+
);
1416+
assert!(parse_is_code_length_err(&too_long));
1417+
assert!(!parse_is_code_length_err(&too_long[..too_long.len() - 1]));
1418+
}
11781419
}

0 commit comments

Comments
 (0)