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 }