Bolt11Invoice.fromString skips p, h and s fields of the wrong length

Open Beginner friendly
#3,418 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
84/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
scala
Domain
backend, payments

Research direction

Read eclair-core/src/main/scala/fr/acinq/eclair/payment/Bolt11Invoice.scala around the InvalidTag1, InvalidTag23 and InvalidTag16 decoding branches, then review the related tests in eclair-core/src/test/scala/fr/acinq/eclair/payment/Bolt11InvoiceSpec.scala. Run ./mvnw test -pl eclair-core -Dsuites='*Bolt11InvoiceSpec'; done means invoices with 51-group p, h or s fields fail to decode, as the supplied test expects.

Written by the indexing model from the issue text.

Description

Bolt11Invoice.fromString skips a 51-group p, h or s field and decodes the invoice instead of failing. This happens on master at 06716fce and in v0.14.5.

The case below, added to eclair-core/src/test/scala/fr/acinq/eclair/payment/Bolt11InvoiceSpec.scala, builds three invoices from the BOLT 11 cup of coffee example, each with one wrong-length field: a 51-group h, a 51-group p and a 51-group s.

// BOLT 11 example "Please send $3 for a cup of coffee to the same peer, within one minute".
val cupOfCoffee: Bolt11Invoice = Bolt11Invoice.fromString("lnbc2500u1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpu9qrsgquk0rl77nj30yxdy8j9vdx85fkpmdla2087ne0xh8nhedh8w27kyke0lp53ut353s06fv3qfegext0eh0ymjpf39tuven09sam30g4vgpfna3rh").get

test("reject p, h or s fields with an invalid length") {
  // Bolt11: a reader MUST fail an invoice whose p, h, s or n field does not have the correct length.
  def groups(i: Int) = BitVector.fill(i * 5)(high = false)
  val wrongLength = List(InvalidTag23(groups(51)), InvalidTag1(groups(51)), InvalidTag16(groups(51)))
  for (bad <- wrongLength) {
    val invoice = cupOfCoffee.copy(tags = cupOfCoffee.tags :+ bad).sign(priv)
    assert(Bolt11Invoice.fromString(invoice.toString).isFailure)
  }
}

./mvnw test -pl eclair-core -Dsuites='*Bolt11InvoiceSpec' reports the case failing.

- reject p, h or s fields with an invalid length *** FAILED ***
  Bolt11Invoice.fromString(invoice.toString).isFailure was false (Bolt11InvoiceSpec.scala:686)
Tests: succeeded 37, failed 1, canceled 0, ignored 0, pending 0

The codec reads those fields as InvalidTag1, InvalidTag23 and InvalidTag16 at lines 411-414, 439-442 and 429-432. The constructor counts only the fields of the right length, so a wrong-length field does not stop the decode. The test "ignore hash tags with invalid length" at Bolt11InvoiceSpec.scala:450-451 still quotes the earlier skip rule, which BOLT 11 replaced in commit 68881992 in June 2025.

fromString should fail on all three. BOLT 11, Tagged Fields, line 214 says a reader "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)".

Dominant language
Scala
Stars
1.3k
Forks
285
Avg merge
20h 22m
Merged PRs (30d)
28

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from ACINQ/eclair

All issues in ACINQ/eclair

Similar issues

More Scala issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.