@@ -159,6 +159,10 @@ pub const DEFAULT_MIN_FINAL_CLTV_EXPIRY_DELTA: u64 = 18;
159159/// consistency is more important.
160160pub const MAX_LENGTH : usize = 7089 ;
161161
162+ /// The maximum length of a tagged field in a BOLT11 invoice. This is 1023 * 5 bits (i.e., 639
163+ /// bytes).
164+ pub const MAX_TAGGED_FIELD_DATA_BYTES : usize = 639 ;
165+
162166/// The [`bech32::Bech32`] checksum algorithm, with extended max length suitable
163167/// for BOLT11 invoices.
164168pub enum Bolt11Bech32 { }
@@ -886,7 +890,11 @@ impl<D: tb::Bool, H: tb::Bool, T: tb::Bool, C: tb::Bool, S: tb::Bool>
886890 pub fn optional_payment_metadata (
887891 mut self , payment_metadata : Vec < u8 > ,
888892 ) -> InvoiceBuilder < D , H , T , C , S , tb:: True > {
889- self . tagged_fields . push ( TaggedField :: PaymentMetadata ( payment_metadata) ) ;
893+ if payment_metadata. len ( ) > MAX_TAGGED_FIELD_DATA_BYTES {
894+ self . error = Some ( CreationError :: PaymentMetadataTooLong ) ;
895+ } else {
896+ self . tagged_fields . push ( TaggedField :: PaymentMetadata ( payment_metadata) ) ;
897+ }
890898 let mut found_features = false ;
891899 for field in self . tagged_fields . iter_mut ( ) {
892900 if let TaggedField :: Features ( f) = field {
@@ -1676,12 +1684,12 @@ impl TaggedField {
16761684}
16771685
16781686impl Description {
1679- /// Creates a new `Description` if `description` is at most 1023 * 5 bits (i.e., 639 bytes)
1687+ /// Creates a new `Description` if `description` is at most [`MAX_TAGGED_FIELD_DATA_BYTES`]
16801688 /// long, and returns [`CreationError::DescriptionTooLong`] otherwise.
16811689 ///
16821690 /// Please note that single characters may use more than one byte due to UTF8 encoding.
16831691 pub fn new ( description : String ) -> Result < Description , CreationError > {
1684- if description. len ( ) > 639 {
1692+ if description. len ( ) > MAX_TAGGED_FIELD_DATA_BYTES {
16851693 Err ( CreationError :: DescriptionTooLong )
16861694 } else {
16871695 Ok ( Description ( UntrustedString ( description) ) )
@@ -1798,6 +1806,9 @@ pub enum CreationError {
17981806 /// The supplied description string was longer than 639 __bytes__ (see [`Description::new`])
17991807 DescriptionTooLong ,
18001808
1809+ /// The supplied payment metadata was longer than 639 __bytes__
1810+ PaymentMetadataTooLong ,
1811+
18011812 /// The specified route has too many hops and can't be encoded
18021813 RouteTooLong ,
18031814
@@ -1820,6 +1831,7 @@ impl Display for CreationError {
18201831 fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
18211832 match self {
18221833 CreationError :: DescriptionTooLong => f. write_str ( "The supplied description string was longer than 639 bytes" ) ,
1834+ CreationError :: PaymentMetadataTooLong => f. write_str ( "The supplied payment metadata was longer than 639 bytes" ) ,
18231835 CreationError :: RouteTooLong => f. write_str ( "The specified route has too many hops and can't be encoded" ) ,
18241836 CreationError :: TimestampOutOfBounds => f. write_str ( "The Unix timestamp of the supplied date is less than zero or greater than 35-bits" ) ,
18251837 CreationError :: InvalidAmount => f. write_str ( "The supplied millisatoshi amount was greater than the total bitcoin supply" ) ,
@@ -2276,6 +2288,10 @@ mod test {
22762288 let long_desc_res = builder. clone ( ) . description ( too_long_string) . build_raw ( ) ;
22772289 assert_eq ! ( long_desc_res, Err ( CreationError :: DescriptionTooLong ) ) ;
22782290
2291+ let long_metadata_res =
2292+ builder. clone ( ) . description ( "Test" . into ( ) ) . payment_metadata ( vec ! [ 0u8 ; 640 ] ) . build_raw ( ) ;
2293+ assert_eq ! ( long_metadata_res, Err ( CreationError :: PaymentMetadataTooLong ) ) ;
2294+
22792295 let route_hop = RouteHintHop {
22802296 src_node_id : PublicKey :: from_slice (
22812297 & [
0 commit comments