Skip to content

What should the sign_invoice API look like? #3227

Closed
@apoelstra

Description

@apoelstra

The NodeSigner::sign_invoice method currently has a pretty crappy API which pretty-much guarantees needless allocations and extra conversions.

The data to be signed consists of an ASCII HRP followed by the non-HRP data of a Lightning invoice encoded as a bytestring. BTW, where is this specified? It it supposed to be the HRP or is it just a "coincidence" that both the bech32 strings and the signed data have the HRP data like this). Currently the API takes this data directly, by taking the HRP as a &[u8], and taking the non-HRP data as a &[u5], which it then internally converts to a bytestring.

This has the following issues:

  • It requires the user to get a &[u5] from somewhere that specifically represents the non-HRP non-checksum data of an invoice. This object must be specifically constructed and serves no other purpose. Currently it is constructed by the allocation-heavy RawDataPart::to_base32 function but in a later version of rust-bech32 we will lose that method.
  • It requires the user to have all the data available in a slice, which basically means that the caller needs to construct Vecs. But the API just takes this raw data and feeds it into a hash engine. If it were able to take a streaming source of bytes (an io::Read or a core::iter::Iterator) we could avoid ever allocating a vector.

Ideally this function would accept a "fully parsed bolt11 invoice", but the type for this is lightning-invoice::RawBolt11Invoice, which is not available in rust-lightning. Alternately it could accept a bech32 string and attempt to parse it itself, but then it would need to deal with error paths related to string parsing. Still alternately it could take a sha256::Hash directly, expecting the caller to do the hashing, but this is a potentially dangerous API (though not that the existing one is any safer..).

For now, a simple and obvious improvement would be for the method to take a &[u8] rather than a &[u5]. Then it could avoid doing an expensive conversion from base 32 to 256 and simply feed its input into a hash engine. But it still forces the caller to produce a Vec<u8> that would just be thrown away.

Where is this API used and what are its requirements?

Related to #3195

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions