github.com/decred/dcrlnd@v0.7.6/lnwire/extra_bytes.go (about)

     1  package lnwire
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  
     9  	"github.com/decred/dcrlnd/tlv"
    10  )
    11  
    12  // ExtraOpaqueData is the set of data that was appended to this message, some
    13  // of which we may not actually know how to iterate or parse. By holding onto
    14  // this data, we ensure that we're able to properly validate the set of
    15  // signatures that cover these new fields, and ensure we're able to make
    16  // upgrades to the network in a forwards compatible manner.
    17  type ExtraOpaqueData []byte
    18  
    19  // Encode attempts to encode the raw extra bytes into the passed io.Writer.
    20  func (e *ExtraOpaqueData) Encode(w *bytes.Buffer) error {
    21  	eBytes := []byte((*e)[:])
    22  	if err := WriteBytes(w, eBytes); err != nil {
    23  		return err
    24  	}
    25  
    26  	return nil
    27  }
    28  
    29  // Decode attempts to unpack the raw bytes encoded in the passed io.Reader as a
    30  // set of extra opaque data.
    31  func (e *ExtraOpaqueData) Decode(r io.Reader) error {
    32  	// First, we'll attempt to read a set of bytes contained within the
    33  	// passed io.Reader (if any exist).
    34  	rawBytes, err := ioutil.ReadAll(r)
    35  	if err != nil {
    36  		return err
    37  	}
    38  
    39  	// If we _do_ have some bytes, then we'll swap out our backing pointer.
    40  	// This ensures that any struct that embeds this type will properly
    41  	// store the bytes once this method exits.
    42  	if len(rawBytes) > 0 {
    43  		*e = ExtraOpaqueData(rawBytes)
    44  	} else {
    45  		*e = make([]byte, 0)
    46  	}
    47  
    48  	return nil
    49  }
    50  
    51  // PackRecords attempts to encode the set of tlv records into the target
    52  // ExtraOpaqueData instance. The records will be encoded as a raw TLV stream
    53  // and stored within the backing slice pointer.
    54  func (e *ExtraOpaqueData) PackRecords(recordProducers ...tlv.RecordProducer) error {
    55  	// First, assemble all the records passed in in series.
    56  	records := make([]tlv.Record, 0, len(recordProducers))
    57  	for _, producer := range recordProducers {
    58  		records = append(records, producer.Record())
    59  	}
    60  
    61  	// Ensure that the set of records are sorted before we encode them into
    62  	// the stream, to ensure they're canonical.
    63  	tlv.SortRecords(records)
    64  
    65  	tlvStream, err := tlv.NewStream(records...)
    66  	if err != nil {
    67  		return err
    68  	}
    69  
    70  	var extraBytesWriter bytes.Buffer
    71  	if err := tlvStream.Encode(&extraBytesWriter); err != nil {
    72  		return err
    73  	}
    74  
    75  	*e = ExtraOpaqueData(extraBytesWriter.Bytes())
    76  
    77  	return nil
    78  }
    79  
    80  // ExtractRecords attempts to decode any types in the internal raw bytes as if
    81  // it were a tlv stream. The set of raw parsed types is returned, and any
    82  // passed records (if found in the stream) will be parsed into the proper
    83  // tlv.Record.
    84  func (e *ExtraOpaqueData) ExtractRecords(recordProducers ...tlv.RecordProducer) (
    85  	tlv.TypeMap, error) {
    86  
    87  	// First, assemble all the records passed in in series.
    88  	records := make([]tlv.Record, 0, len(recordProducers))
    89  	for _, producer := range recordProducers {
    90  		records = append(records, producer.Record())
    91  	}
    92  
    93  	extraBytesReader := bytes.NewReader(*e)
    94  
    95  	tlvStream, err := tlv.NewStream(records...)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  
   100  	return tlvStream.DecodeWithParsedTypes(extraBytesReader)
   101  }
   102  
   103  // EncodeMessageExtraData encodes the given recordProducers into the given
   104  // extraData.
   105  func EncodeMessageExtraData(extraData *ExtraOpaqueData,
   106  	recordProducers ...tlv.RecordProducer) error {
   107  
   108  	// Treat extraData as a mutable reference.
   109  	if extraData == nil {
   110  		return fmt.Errorf("extra data cannot be nil")
   111  	}
   112  
   113  	// Pack in the series of TLV records into this message. The order we
   114  	// pass them in doesn't matter, as the method will ensure that things
   115  	// are all properly sorted.
   116  	return extraData.PackRecords(recordProducers...)
   117  }