An overflow can occur when multiplying the offer amount by the requested
quantity when no amount is given in the request. Return an error instead
of overflowing.
An overflow can occur when multiplying the offer amount by the requested
quantity when checking if the given amount is enough. Return an error
instead of overflowing.
In order to fuzz test Bech32Encode parsing independent of the underlying
message deserialization, the trait needs to be exposed. Conditionally
expose it only for fuzzing.
An invoice request is serialized as a TLV stream and encoded as bytes.
Add a fuzz test that parses the TLV stream and deserializes the
underlying InvoiceRequest. Then compare the original bytes with those
obtained by re-serializing the InvoiceRequest.
A refund is serialized as a TLV stream and encoded in bech32 without a
checksum. Add a fuzz test that parses the unencoded TLV stream and
deserializes the underlying Refund. Then compare the original bytes with
those obtained by re-serializing the Refund.
BlindedPayInfo fields need to be public in order to construct one for
fuzz tests. Typically, they would be constructed from ChannelUpdateInfo
for public channels and ChannelDetails for unannounced channels. For
now, make the fields public so they can be constructed manually.
An offer is serialized as a TLV stream and encoded in bech32 without a
checksum. Add a fuzz test that parses the unencoded TLV stream and
deserializes the underlying Offer. Then compare the original bytes with
those obtained by re-serializing the Offer.
Both Refund::respond_with and InvoiceRequest::respond_with take a
created_at since the Unix epoch Duration in no-std. However, this can
cause problems if two downstream dependencies want to use the lightning
crate with different feature flags set. Instead, define
respond_with_no_std versions of each method in addition to a
respond_with version in std.
The offer_metadata was optional but is redundant with invreq_metadata
(i.e., payer_metadata) for refunds. It is now disallowed in the spec and
was already unsupported by RefundBuilder.
The spec always allowed this but the reason was unclear. It's useful if
the refund is for an invoice paid for offer where a quantity was given
in the request. The description in the refund would be from the offer,
which may have given a unit for each item. So allowing a quantity makes
it clear how many items the refund is for.
The spec was modified to allow setting offer_quantity_max explicitly to
one. This is to support a use case where more than one item is supported
but only one item is left in the inventory. Introduce a Quantity::One
variant to replace Quantity::Bounded(1) so the later can be used for the
explicit setting.
For std builds, Invoice::created_at can be automatically set upon
construction using SystemTime::now() offset by SystemTime::UNIX_EPOCH.
Change InvoiceRequest::respond_with and Refund::respond_with to only
take a created_at parameter in no-std builds.
Add a builder for creating invoices for a refund and required fields.
Other settings are optional and duplicative settings will override
previous settings. Building produces a semantically valid `invoice`
message for the refund, which then can be signed with the key associated
with the provided signing pubkey.
Add a builder for creating invoices for an offer from a given request
and required fields. Other settings are optional and duplicative
settings will override previous settings. Building produces a
semantically valid `invoice` message for the offer, which then can be
signed with the key associated with the offer's signing pubkey.
Define an interface for BOLT 12 `invoice` messages. The underlying
format consists of the original bytes and the parsed contents.
The bytes are later needed for serialization. This is because it must
mirror all the `offer` and `invoice_request` TLV records, including
unknown ones, which aren't represented in the contents.
Invoices may be created for an Offer (from an InvoiceRequest) or for a
Refund. The primary difference is how the signing pubkey is given -- by
the writer of the offer or the reader of the refund.
When using bytes from an InvoiceRequest to constructing bytes for an
Invoice, any signature TLV records in the bytes must be excluded. Define
a wrapper for encoding such pre-serialized bytes in this manner. This
will allow the forthcoming InvoiceBuilder to construct bytes for an
Invoice properly.
Provide a helper for skipping signature TLV records from a TLV stream.
This prevents needing to duplicate the check for signature TLV records
when writing a TLV stream without signatures in an upcoming commit.
Most BOLT 12 features are used as the value of a TLV record and thus
don't use an explicit length. One exception is the features inside the
blinded payinfo subtype since the TLV record contains a list of them.
However, these features are also used in the BOLT 4 encrypted_data_tlv
TLV stream as a single record, where the length is implicit.
Implement Readable and Writeable for Features wrapped in WithoutLength
such that either serialization can be used where required.
Add a builder for creating refunds given a payer_id and other required
fields. Other settings are optional and duplicative settings will
override previous settings. Building produces a semantically valid
`invoice_request` message representing the refund, which then may be
communicated out of band (e.g., via QR code).
Define an interface for BOLT 12 refunds (i.e., an `invoice_request`
message without an `offer_node_id`). A refund is more generally an
"offer for money". While it is encoded using the same TLV streams as an
`invoice_request` message, it has different semantics.
A BOLT 12 test vector uses an `invoice_request` message that has a
currency, which aren't supported, so using OfferBuilder::build_unchecked
is required to avoid a panic.
Add a builder for creating invoice requests for an offer given a
payer_id. Other settings may be optional depending on the offer and
duplicative settings will override previous settings. Building produces
a semantically valid `invoice_request` message for the offer, which then
can be signed for the payer_id.
When reading an offer, an `invoice_request` message is sent over the
wire. Implement Writeable for encoding the message and TryFrom for
decoding it by defining in terms of TLV streams. These streams represent
content for the payer metadata (0), reflected `offer` (1-79),
`invoice_request` (80-159), and signature (240).
Offers uses a merkle root hash construction for signature calculation
and verification. Add a submodule implementing this so that it can be
used when parsing and signing invoice_request and invoice messages.
Define an interface for BOLT 12 `invoice_request` messages. The
underlying format consists of the original bytes and the parsed
contents.
The bytes are later needed when constructing an `invoice` message. This
is because it must mirror all the `offer` and `invoice_request` TLV
records, including unknown ones, which aren't represented in the
contents.
The contents will be used in `invoice` messages to avoid duplication.
Some fields while required in a typical user-pays-merchant flow may not
be necessary in the merchant-pays-user flow (e.g., refund, ATM).
BOLT 12 messages are limited to a range of TLV record types. Refactor
decode_tlv_stream into a decode_tlv_stream_range macro for limiting
which types are parsed. Requires a SeekReadable trait for rewinding when
a type outside of the range is seen. This allows for composing TLV
streams of different ranges.
Updates offer parsing accordingly and adds a test demonstrating failure
if a type outside of the range is included.
Add common bech32 parsing for BOLT 12 messages. The encoding is similar
to bech32 only without a checksum and with support for continuing
messages across multiple parts.
Messages implementing Bech32Encode are parsed into a TLV stream, which
is converted to the desired message content while performing semantic
checks. Checking after conversion allows for more elaborate checks of
data composed of multiple TLV records and for more meaningful error
messages.
The parsed bytes are also saved to allow creating messages with mirrored
data, even if TLV records are unknown.