lnwire: introduce PureTLVMessage
PureTLVMessage describes an LN message that is a pure TLV stream. If the message includes a signature, it will sign all the TLV records in the inclusive ranges: 0 to 159 and 1000000000 to 2999999999. A comprehensive test is added that shows how two versions of the same message remain forward compatible.
This commit is contained in:
2 files changed
+494
No files matched your search
@@ -0,0 +1,105 @@
|
||||
package lnwire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/lightningnetwork/lnd/tlv"
|
||||
)
|
||||
|
||||
const (
|
||||
// pureTLVUnsignedRangeOneStart defines the start of the first unsigned
|
||||
// TLV range used for pure TLV messages. The range is inclusive of this
|
||||
// number.
|
||||
pureTLVUnsignedRangeOneStart = 160
|
||||
|
||||
// pureTLVSignedSecondRangeStart defines the start of the second signed
|
||||
// TLV range used for pure TLV messages. The range is inclusive of this
|
||||
// number. Note that the first range is the inclusive range of 0-159.
|
||||
pureTLVSignedSecondRangeStart = 1000000000
|
||||
|
||||
// pureTLVUnsignedRangeTwoStart defines the start of the second unsigned
|
||||
// TLV range used for pure TLV message.
|
||||
pureTLVUnsignedRangeTwoStart = 3000000000
|
||||
)
|
||||
|
||||
// PureTLVMessage describes an LN message that is a pure TLV stream. If the
|
||||
// message includes a signature, it will sign all the TLV records in the
|
||||
// inclusive ranges: 0 to 159 and 1000000000 to 2999999999.
|
||||
type PureTLVMessage interface {
|
||||
// AllRecords returns all the TLV records for the message. This will
|
||||
// include all the records we know about along with any that we don't
|
||||
// know about but that fall in the signed TLV range.
|
||||
AllRecords() []tlv.Record
|
||||
}
|
||||
|
||||
// EncodePureTLVMessage encodes the given PureTLVMessage to the given buffer.
|
||||
func EncodePureTLVMessage(msg PureTLVMessage, buf *bytes.Buffer) error {
|
||||
return EncodeRecordsTo(buf, msg.AllRecords())
|
||||
}
|
||||
|
||||
// SerialiseFieldsToSign serialises all the records from the given
|
||||
// PureTLVMessage that fall within the signed TLV range.
|
||||
func SerialiseFieldsToSign(msg PureTLVMessage) ([]byte, error) {
|
||||
// Filter out all the fields not in the signed ranges.
|
||||
var signedRecords []tlv.Record
|
||||
for _, record := range msg.AllRecords() {
|
||||
if InUnsignedRange(record.Type()) {
|
||||
continue
|
||||
}
|
||||
|
||||
signedRecords = append(signedRecords, record)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := EncodeRecordsTo(&buf, signedRecords); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// InUnsignedRange returns true if the given TLV type falls outside the TLV
|
||||
// ranges that the signature of a pure TLV message will cover.
|
||||
func InUnsignedRange(t tlv.Type) bool {
|
||||
return (t >= pureTLVUnsignedRangeOneStart &&
|
||||
t < pureTLVSignedSecondRangeStart) ||
|
||||
t >= pureTLVUnsignedRangeTwoStart
|
||||
}
|
||||
|
||||
// ExtraSignedFields is a type that stores a map from TLV types in the signed
|
||||
// range (for PureMessages) to their corresponding serialised values. This type
|
||||
// can be used to keep around data that we don't yet understand but that we need
|
||||
// for re-composing the wire message since the signature covers these fields.
|
||||
type ExtraSignedFields map[uint64][]byte
|
||||
|
||||
// ExtraSignedFieldsFromTypeMap is a helper that can be used alongside calls to
|
||||
// the tlv.Stream DecodeWithParsedTypesP2P or DecodeWithParsedTypes methods to
|
||||
// extract the tlv type and value pairs in the defined PureTLVMessage signed
|
||||
// range which we have not handled with any of our defined Records. These
|
||||
// methods will return a tlv.TypeMap containing the records that were extracted
|
||||
// from an io.Reader. If the record was know and handled by a defined record,
|
||||
// then the value accompanying the record's type in the map will be nil.
|
||||
// Otherwise, if the record was unhandled, it will be non-nil.
|
||||
func ExtraSignedFieldsFromTypeMap(m tlv.TypeMap) ExtraSignedFields {
|
||||
extraFields := make(ExtraSignedFields)
|
||||
for t, v := range m {
|
||||
// If the value in the type map is nil, then it indicates that
|
||||
// we know this type, and it was handled by one of the records
|
||||
// we passed to the decode function vai the TLV stream.
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// No need to keep this field if it is unknown to us and is not
|
||||
// in the sign range.
|
||||
if InUnsignedRange(t) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Otherwise, this is an un-handled type, so we keep track of
|
||||
// it for signature validation and re-encoding later on.
|
||||
extraFields[uint64(t)] = v
|
||||
}
|
||||
|
||||
return extraFields
|
||||
}
|
||||
Reference in new issue
Block a user