mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 09:53:54 +01:00
7ae4bf0672
This ensures that the caller doesn't need to worry about the TLV type ordering of the records the pass into the function.
124 lines
3.7 KiB
Go
124 lines
3.7 KiB
Go
package lnwire
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
|
|
"github.com/lightningnetwork/lnd/tlv"
|
|
)
|
|
|
|
// ExtraOpaqueData is the set of data that was appended to this message, some
|
|
// of which we may not actually know how to iterate or parse. By holding onto
|
|
// this data, we ensure that we're able to properly validate the set of
|
|
// signatures that cover these new fields, and ensure we're able to make
|
|
// upgrades to the network in a forwards compatible manner.
|
|
type ExtraOpaqueData []byte
|
|
|
|
// Encode attempts to encode the raw extra bytes into the passed io.Writer.
|
|
func (e *ExtraOpaqueData) Encode(w *bytes.Buffer) error {
|
|
eBytes := []byte((*e)[:])
|
|
if err := WriteBytes(w, eBytes); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Decode attempts to unpack the raw bytes encoded in the passed io.Reader as a
|
|
// set of extra opaque data.
|
|
func (e *ExtraOpaqueData) Decode(r io.Reader) error {
|
|
// First, we'll attempt to read a set of bytes contained within the
|
|
// passed io.Reader (if any exist).
|
|
rawBytes, err := ioutil.ReadAll(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// If we _do_ have some bytes, then we'll swap out our backing pointer.
|
|
// This ensures that any struct that embeds this type will properly
|
|
// store the bytes once this method exits.
|
|
if len(rawBytes) > 0 {
|
|
*e = ExtraOpaqueData(rawBytes)
|
|
} else {
|
|
*e = make([]byte, 0)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// PackRecords attempts to encode the set of tlv records into the target
|
|
// ExtraOpaqueData instance. The records will be encoded as a raw TLV stream
|
|
// and stored within the backing slice pointer.
|
|
func (e *ExtraOpaqueData) PackRecords(recordProducers ...tlv.RecordProducer) error {
|
|
// First, assemble all the records passed in in series.
|
|
records := make([]tlv.Record, 0, len(recordProducers))
|
|
for _, producer := range recordProducers {
|
|
records = append(records, producer.Record())
|
|
}
|
|
|
|
// Ensure that the set of records are sorted before we encode them into
|
|
// the stream, to ensure they're canonical.
|
|
tlv.SortRecords(records)
|
|
|
|
tlvStream, err := tlv.NewStream(records...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var extraBytesWriter bytes.Buffer
|
|
if err := tlvStream.Encode(&extraBytesWriter); err != nil {
|
|
return err
|
|
}
|
|
|
|
*e = ExtraOpaqueData(extraBytesWriter.Bytes())
|
|
|
|
return nil
|
|
}
|
|
|
|
// ExtractRecords attempts to decode any types in the internal raw bytes as if
|
|
// it were a tlv stream. The set of raw parsed types is returned, and any
|
|
// passed records (if found in the stream) will be parsed into the proper
|
|
// tlv.Record.
|
|
func (e *ExtraOpaqueData) ExtractRecords(recordProducers ...tlv.RecordProducer) (
|
|
tlv.TypeMap, error) {
|
|
|
|
// First, assemble all the records passed in in series.
|
|
records := make([]tlv.Record, 0, len(recordProducers))
|
|
for _, producer := range recordProducers {
|
|
records = append(records, producer.Record())
|
|
}
|
|
|
|
// Ensure that the set of records are sorted before we attempt to
|
|
// decode from the stream, to ensure they're canonical.
|
|
tlv.SortRecords(records)
|
|
|
|
extraBytesReader := bytes.NewReader(*e)
|
|
|
|
tlvStream, err := tlv.NewStream(records...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Since ExtraOpaqueData is provided by a potentially malicious peer,
|
|
// pass it into the P2P decoding variant.
|
|
return tlvStream.DecodeWithParsedTypesP2P(extraBytesReader)
|
|
}
|
|
|
|
// EncodeMessageExtraData encodes the given recordProducers into the given
|
|
// extraData.
|
|
func EncodeMessageExtraData(extraData *ExtraOpaqueData,
|
|
recordProducers ...tlv.RecordProducer) error {
|
|
|
|
// Treat extraData as a mutable reference.
|
|
if extraData == nil {
|
|
return fmt.Errorf("extra data cannot be nil")
|
|
}
|
|
|
|
// Pack in the series of TLV records into this message. The order we
|
|
// pass them in doesn't matter, as the method will ensure that things
|
|
// are all properly sorted.
|
|
return extraData.PackRecords(recordProducers...)
|
|
}
|