Skip to content

Add optional validation‑skipping decode pathway for Invoice.Decode (private core method + explicit public opt‑out) #70

@nGoline

Description

@nGoline

Summary

Introduce a private decode core with a bool skipValidation switch so callers can optionally skip invoice validation and still inspect parsed fields when something fails. Keep the existing public Decode(...) API unchanged and add a new, explicitly named public method that calls the private core with validation skipped.

Background / Motivation

  • During troubleshooting and tooling scenarios, consumers may want to parse BOLT11 invoices to inspect tagged fields and partial state even when validation would fail.
  • Centralizing validation after parsing (see dependency below) enables a clean separation: parse first, optionally validate after.
  • Current public API must not change; we will provide a new, clearly dangerous/explicit method to opt out of validation.

Dependency

Scope

  • Create a new private core method for Invoice.Decode that accepts a bool skipValidation.
  • Keep the existing public Decode(...) method with the same signature; make it delegate to the new private core with skipValidation: false.
  • Add a new, explicitly named public method that makes it unmistakable validation is skipped; it delegates to the private core with skipValidation: true.

Proposed Changes

  • In src/NLightning.Bolt11/Models/Invoice.cs:
    1. Extract the core logic from the current public static Invoice Decode(...) into a new private static Invoice DecodeInternal(string? invoiceString, BitcoinNetwork? expectedNetwork = null, bool skipValidation = false) (name is illustrative; any consistent internal name is fine).
    2. Update existing public static Invoice Decode(string? invoiceString, BitcoinNetwork? expectedNetwork = null) to call DecodeInternal(invoiceString, expectedNetwork, false).
    3. Add a new public method with a very verbose name (example):
      • public static Invoice DecodeSkippingAllValidation(string? invoiceString, BitcoinNetwork? expectedNetwork = null)
      • This should call DecodeInternal(invoiceString, expectedNetwork, true).
    4. Inside the private core, gate the validation section:
      • If skipValidation is false, run InvoiceValidationService.ValidateInvoice(invoice) (as today) and throw on errors.
      • If skipValidation is true, skip the validation step entirely, still perform signature handling decisions consistent with the goal (either skip signature check as part of validation or keep it if it does not prevent field inspection — clarify in implementation notes/tests).

Acceptance Criteria

  • A new private core decode method exists that takes bool skipValidation and returns an Invoice even when it would otherwise fail validation.
  • The existing public Decode(...) signature remains unchanged and delegates to the private core with skipValidation: false.
  • A new public method with an explicit, verbose name (e.g., DecodeSkippingAllValidationSoYouCanInspectParsedFieldsOnly) delegates to the private core with skipValidation: true.
  • XML docs clearly warn that the new method is unsafe for production and is intended solely for diagnostics/inspection.
  • Unit tests cover both pathways (normal validate vs. skip validate) and confirm that when skipping, fields are still accessible even for invalid invoices.
  • This change is implemented only after issue Move uniqueness and mutual‑exclusivity checks from TaggedFieldList.Add to InvoiceValidationService #69 is merged; PR notes and commit messages reference the dependency.

Testing Plan

  • Add tests in test/NLightning.Bolt11.Tests for:
    • Normal path: Decode(...) still validates and throws (via InvoiceSerializationException) on invalid invoices.
    • Skip path: DecodeSkippingAllValidationSoYouCanInspectParsedFieldsOnly(...) returns an Invoice with parsed TaggedFieldList despite invalid combinations; tests assert on the presence of fields and that no validation exception is thrown.
    • Edge cases: malformed Bech32 or irrecoverable parse errors should still throw from the decode core (skip does not bypass deserialization failures, only validation).

Risks / Considerations

  • Make sure skip‑validation does not accidentally bypass essential integrity checks that would lead to undefined state (e.g., signature parsing errors vs. signature validation): parsing should succeed, but cryptographic verification may be skipped or gated behind skipValidation if it would throw. Document any behavior.
  • Very explicit method naming and XML docs are important to avoid misuse.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions