@@ -5,10 +5,13 @@ import (
55 "fmt"
66 "io"
77 "math"
8+ "net/url"
89
910 "github.com/btcsuite/btcd/blockchain"
11+ "github.com/btcsuite/btcd/btcec/v2"
1012 "github.com/btcsuite/btcd/wire"
1113 "github.com/lightninglabs/taproot-assets/asset"
14+ "github.com/lightninglabs/taproot-assets/fn"
1215 "github.com/lightningnetwork/lnd/tlv"
1316)
1417
@@ -463,3 +466,179 @@ func GenesisRevealDecoder(r io.Reader, val any, buf *[8]byte, l uint64) error {
463466
464467 return tlv .NewTypeForEncodingErr (val , "GenesisReveal" )
465468}
469+
470+ // EUint32Option encodes a uint32 option. If the value is not set, we'll encode
471+ // it as a zero-length record. But that means that the type and length fields
472+ // will still be encoded, which is different from the record not being present
473+ // at all. If the distinction should be made (e.g. to not re-encode old records
474+ // that didn't have that field at all with the new zero-length record), the
475+ // caller needs to handle that by conditionally including or not including the
476+ // record.
477+ func EUint32Option (w io.Writer , val interface {}, buf * [8 ]byte ) error {
478+ if t , ok := val .(* fn.Option [uint32 ]); ok {
479+ return fn .MapOptionZ (* t , func (value uint32 ) error {
480+ return tlv .EUint32T (w , value , buf )
481+ })
482+ }
483+ return tlv .NewTypeForEncodingErr (val , "*fn.Option[uint32]" )
484+ }
485+
486+ // DUint32Option decodes a uint32 option.
487+ func DUint32Option (r io.Reader , val interface {}, buf * [8 ]byte , l uint64 ) error {
488+ if t , ok := val .(* fn.Option [uint32 ]); ok {
489+ if l == 0 {
490+ * t = fn .None [uint32 ]()
491+ return nil
492+ }
493+
494+ var newVal uint32
495+ if err := tlv .DUint32 (r , & newVal , buf , l ); err != nil {
496+ return err
497+ }
498+
499+ * t = fn .Some (newVal )
500+
501+ return nil
502+ }
503+ return tlv .NewTypeForDecodingErr (val , "*fn.Option[uint32]" , l , l )
504+ }
505+
506+ // UrlSliceOptionEncoder encodes a URL option. If the value is not set, or the
507+ // slice is empty, we'll encode it as a zero-length record. But that means that
508+ // the type and length fields will still be encoded, which is different from the
509+ // record not being present at all. If the distinction should be made (e.g. to
510+ // not re-encode old records that didn't have that field at all with the new
511+ // zero-length record), the caller needs to handle that by conditionally
512+ // including or not including the record.
513+ func UrlSliceOptionEncoder (w io.Writer , val any , buf * [8 ]byte ) error {
514+ if t , ok := val .(* fn.Option [[]url.URL ]); ok {
515+ return fn .MapOptionZ (* t , func (value []url.URL ) error {
516+ numValues := uint64 (len (value ))
517+ if numValues == 0 {
518+ return nil
519+ }
520+
521+ err := tlv .WriteVarInt (w , numValues , buf )
522+ if err != nil {
523+ return err
524+ }
525+
526+ for _ , addr := range value {
527+ addrBytes := []byte (addr .String ())
528+ err := asset .InlineVarBytesEncoder (
529+ w , & addrBytes , buf ,
530+ )
531+ if err != nil {
532+ return err
533+ }
534+ }
535+
536+ return nil
537+ })
538+ }
539+ return tlv .NewTypeForEncodingErr (val , "*fn.Option[[]url.URL]" )
540+ }
541+
542+ // UrlSliceOptionDecoder decodes a URL option.
543+ func UrlSliceOptionDecoder (r io.Reader , val any , buf * [8 ]byte , l uint64 ) error {
544+ if l > MaxNumCanonicalUniverseURLs * MaxCanonicalUniverseURLLength {
545+ return tlv .ErrRecordTooLarge
546+ }
547+
548+ if t , ok := val .(* fn.Option [[]url.URL ]); ok {
549+ if l == 0 {
550+ * t = fn .None [[]url.URL ]()
551+
552+ return nil
553+ }
554+
555+ numValues , err := tlv .ReadVarInt (r , buf )
556+ if err != nil {
557+ return err
558+ }
559+
560+ if numValues > MaxNumCanonicalUniverseURLs {
561+ return tlv .ErrRecordTooLarge
562+ }
563+
564+ urls := make ([]url.URL , 0 , numValues )
565+ for i := uint64 (0 ); i < numValues ; i ++ {
566+ var urlBytes []byte
567+ err := asset .InlineVarBytesDecoder (
568+ r , & urlBytes , buf ,
569+ MaxCanonicalUniverseURLLength ,
570+ )
571+ if err != nil {
572+ return err
573+ }
574+
575+ addr , err := url .ParseRequestURI (string (urlBytes ))
576+ if err != nil {
577+ return err
578+ }
579+ urls = append (urls , * addr )
580+ }
581+
582+ * t = fn .Some (urls )
583+
584+ return nil
585+ }
586+ return tlv .NewTypeForDecodingErr (val , "*fn.Option[[]url.URL]" , l , l )
587+ }
588+
589+ // PublicKeyOptionEncoder encodes a public key option. If the value is not set,
590+ // we'll encode it as a zero-length record. But that means that the type and
591+ // length fields will still be encoded, which is different from the record not
592+ // being present at all. If the distinction should be made (e.g. to not
593+ // re-encode old records that didn't have that field at all with the new
594+ // zero-length record), the caller needs to handle that by conditionally
595+ // including or not including the record.
596+ func PublicKeyOptionEncoder (w io.Writer , val any , buf * [8 ]byte ) error {
597+ if t , ok := val .(* fn.Option [btcec.PublicKey ]); ok {
598+ return fn .MapOptionZ (* t , func (value btcec.PublicKey ) error {
599+ if value == emptyKey {
600+ return nil
601+ }
602+
603+ ptr := & value
604+ return asset .CompressedPubKeyEncoder (w , & ptr , buf )
605+ })
606+ }
607+ return tlv .NewTypeForEncodingErr (val , "*fn.Option[btcec.PublicKey]" )
608+ }
609+
610+ // PublicKeyOptionDecoder decodes a public key option.
611+ func PublicKeyOptionDecoder (r io.Reader , val any , buf * [8 ]byte ,
612+ l uint64 ) error {
613+
614+ if l > btcec .PubKeyBytesLenCompressed {
615+ return tlv .ErrRecordTooLarge
616+ }
617+
618+ if t , ok := val .(* fn.Option [btcec.PublicKey ]); ok {
619+ if l == 0 {
620+ * t = fn .None [btcec.PublicKey ]()
621+
622+ return nil
623+ }
624+
625+ var result * btcec.PublicKey
626+ err := asset .CompressedPubKeyDecoder (r , & result , buf , l )
627+ if err != nil {
628+ return err
629+ }
630+
631+ if result == nil || * result == emptyKey {
632+ * t = fn .None [btcec.PublicKey ]()
633+
634+ return nil
635+ }
636+
637+ * t = fn .Some (* result )
638+
639+ return nil
640+ }
641+ return tlv .NewTypeForDecodingErr (
642+ val , "*fn.Option[btcec.PublicKey]" , l , l ,
643+ )
644+ }
0 commit comments