Skip to content

Commit 1f580d7

Browse files
authored
Merge pull request #911 from lightninglabs/rfqmsg-version
Add version fields to RFQ wire messages
2 parents d306371 + 17c1dca commit 1f580d7

11 files changed

+245
-34
lines changed

rfqmsg/buy_accept.go

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,23 @@ import (
1515
const (
1616
// Buy accept message type field TLV types.
1717

18-
TypeBuyAcceptID tlv.Type = 0
19-
TypeBuyAcceptAskPrice tlv.Type = 2
20-
TypeBuyAcceptExpiry tlv.Type = 4
21-
TypeBuyAcceptSignature tlv.Type = 6
22-
TypeBuyAcceptAssetID tlv.Type = 8
18+
TypeBuyAcceptVersion tlv.Type = 0
19+
TypeBuyAcceptID tlv.Type = 2
20+
TypeBuyAcceptAskPrice tlv.Type = 4
21+
TypeBuyAcceptExpiry tlv.Type = 6
22+
TypeBuyAcceptSignature tlv.Type = 8
23+
TypeBuyAcceptAssetID tlv.Type = 10
2324
)
2425

26+
func TypeRecordBuyAcceptVersion(version *WireMsgDataVersion) tlv.Record {
27+
const recordSize = 1
28+
29+
return tlv.MakeStaticRecord(
30+
TypeBuyAcceptVersion, version, recordSize,
31+
WireMsgDataVersionEncoder, WireMsgDataVersionDecoder,
32+
)
33+
}
34+
2535
func TypeRecordBuyAcceptID(id *ID) tlv.Record {
2636
const recordSize = 32
2737

@@ -80,9 +90,18 @@ func TypeRecordBuyAcceptAssetID(assetID **asset.ID) tlv.Record {
8090
)
8191
}
8292

93+
const (
94+
// latestBuyAcceptVersion is the latest supported buy accept wire
95+
// message data field version.
96+
latestBuyAcceptVersion = V0
97+
)
98+
8399
// buyAcceptMsgData is a struct that represents the data field of a quote
84100
// accept message.
85101
type buyAcceptMsgData struct {
102+
// Version is the version of the message data.
103+
Version WireMsgDataVersion
104+
86105
// ID represents the unique identifier of the quote request message that
87106
// this response is associated with.
88107
ID ID
@@ -104,6 +123,7 @@ type buyAcceptMsgData struct {
104123
// encodeRecords provides all TLV records for encoding.
105124
func (q *buyAcceptMsgData) encodeRecords() []tlv.Record {
106125
records := []tlv.Record{
126+
TypeRecordBuyAcceptVersion(&q.Version),
107127
TypeRecordBuyAcceptID(&q.ID),
108128
TypeRecordBuyAcceptAskPrice(&q.AskPrice),
109129
TypeRecordBuyAcceptExpiry(&q.Expiry),
@@ -122,6 +142,7 @@ func (q *buyAcceptMsgData) encodeRecords() []tlv.Record {
122142
// decodeRecords provides all TLV records for decoding.
123143
func (q *buyAcceptMsgData) decodeRecords() []tlv.Record {
124144
return []tlv.Record{
145+
TypeRecordBuyAcceptVersion(&q.Version),
125146
TypeRecordBuyAcceptID(&q.ID),
126147
TypeRecordBuyAcceptAskPrice(&q.AskPrice),
127148
TypeRecordBuyAcceptExpiry(&q.Expiry),
@@ -181,6 +202,7 @@ func NewBuyAcceptFromRequest(request BuyRequest, askPrice lnwire.MilliSatoshi,
181202
Peer: request.Peer,
182203
AssetAmount: request.AssetAmount,
183204
buyAcceptMsgData: buyAcceptMsgData{
205+
Version: latestBuyAcceptVersion,
184206
ID: request.ID,
185207
AskPrice: askPrice,
186208
Expiry: expiry,
@@ -205,6 +227,12 @@ func NewBuyAcceptFromWireMsg(wireMsg WireMessage) (*BuyAccept, error) {
205227
"message data: %w", err)
206228
}
207229

230+
// Ensure that the message version is supported.
231+
if msgData.Version > latestBuyAcceptVersion {
232+
return nil, fmt.Errorf("unsupported buy accept message "+
233+
"version: %d", msgData.Version)
234+
}
235+
208236
return &BuyAccept{
209237
Peer: wireMsg.Peer,
210238
buyAcceptMsgData: msgData,

rfqmsg/buy_accept_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ func TestBuyAcceptMsgDataEncodeDecode(t *testing.T) {
6060
testCases := []struct {
6161
testName string
6262

63+
version WireMsgDataVersion
6364
id ID
6465
askPrice lnwire.MilliSatoshi
6566
expiry uint64
@@ -68,6 +69,7 @@ func TestBuyAcceptMsgDataEncodeDecode(t *testing.T) {
6869
}{
6970
{
7071
testName: "all fields populated with basic values",
72+
version: latestBuyAcceptVersion,
7173
id: id,
7274
askPrice: 1000,
7375
expiry: 42000,
@@ -82,6 +84,7 @@ func TestBuyAcceptMsgDataEncodeDecode(t *testing.T) {
8284
for _, tc := range testCases {
8385
t.Run(tc.testName, func(tt *testing.T) {
8486
msg := buyAcceptMsgData{
87+
Version: tc.version,
8588
ID: tc.id,
8689
AskPrice: tc.askPrice,
8790
Expiry: tc.expiry,

rfqmsg/buy_request.go

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,23 @@ import (
1717
const (
1818
// Buy request message type field TLV types.
1919

20-
TypeBuyRequestID tlv.Type = 0
21-
TypeBuyRequestAssetID tlv.Type = 1
22-
TypeBuyRequestAssetGroupKey tlv.Type = 3
23-
TypeBuyRequestAssetAmount tlv.Type = 4
24-
TypeBuyRequestBidPrice tlv.Type = 6
20+
TypeBuyRequestVersion tlv.Type = 0
21+
TypeBuyRequestID tlv.Type = 2
22+
TypeBuyRequestAssetID tlv.Type = 3
23+
TypeBuyRequestAssetGroupKey tlv.Type = 5
24+
TypeBuyRequestAssetAmount tlv.Type = 6
25+
TypeBuyRequestBidPrice tlv.Type = 8
2526
)
2627

28+
func TypeRecordBuyRequestVersion(version *WireMsgDataVersion) tlv.Record {
29+
const recordSize = 1
30+
31+
return tlv.MakeStaticRecord(
32+
TypeBuyRequestVersion, version, recordSize,
33+
WireMsgDataVersionEncoder, WireMsgDataVersionDecoder,
34+
)
35+
}
36+
2737
func TypeRecordBuyRequestID(id *ID) tlv.Record {
2838
const recordSize = 32
2939

@@ -121,9 +131,18 @@ func TypeRecordBuyRequestBidPrice(bid *lnwire.MilliSatoshi) tlv.Record {
121131
)
122132
}
123133

134+
const (
135+
// latestBuyRequestVersion is the latest supported buy request wire
136+
// message data field version.
137+
latestBuyRequestVersion = V0
138+
)
139+
124140
// buyRequestMsgData is a struct that represents the message data from an asset
125141
// buy quote request message.
126142
type buyRequestMsgData struct {
143+
// Version is the version of the message data.
144+
Version WireMsgDataVersion
145+
127146
// ID is the unique identifier of the quote request.
128147
ID ID
129148

@@ -154,15 +173,22 @@ func (q *buyRequestMsgData) Validate() error {
154173
"non-nil")
155174
}
156175

176+
// Ensure that the message version is supported.
177+
if q.Version > latestBuyRequestVersion {
178+
return fmt.Errorf("unsupported buy request message version: %d",
179+
q.Version)
180+
}
181+
157182
return nil
158183
}
159184

160185
// EncodeRecords determines the non-nil records to include when encoding an at
161186
// runtime.
162187
func (q *buyRequestMsgData) encodeRecords() []tlv.Record {
163-
var records []tlv.Record
164-
165-
records = append(records, TypeRecordBuyRequestID(&q.ID))
188+
records := []tlv.Record{
189+
TypeRecordBuyRequestVersion(&q.Version),
190+
TypeRecordBuyRequestID(&q.ID),
191+
}
166192

167193
if q.AssetID != nil {
168194
records = append(
@@ -206,6 +232,7 @@ func (q *buyRequestMsgData) Bytes() ([]byte, error) {
206232
// DecodeRecords provides all TLV records for decoding.
207233
func (q *buyRequestMsgData) decodeRecords() []tlv.Record {
208234
return []tlv.Record{
235+
TypeRecordBuyRequestVersion(&q.Version),
209236
TypeRecordBuyRequestID(&q.ID),
210237
TypeRecordBuyRequestAssetID(&q.AssetID),
211238
TypeRecordBuyRequestAssetGroupKey(&q.AssetGroupKey),
@@ -248,6 +275,7 @@ func NewBuyRequest(peer route.Vertex, assetID *asset.ID,
248275
return &BuyRequest{
249276
Peer: peer,
250277
buyRequestMsgData: buyRequestMsgData{
278+
Version: latestBuyRequestVersion,
251279
ID: id,
252280
AssetID: assetID,
253281
AssetGroupKey: assetGroupKey,

rfqmsg/buy_request_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,25 @@ func TestBuyRequestMsgDataEncodeDecode(t *testing.T) {
2727
testCases := []struct {
2828
testName string
2929

30+
version WireMsgDataVersion
3031
id ID
3132
assetId *asset.ID
3233
assetGroupKey *btcec.PublicKey
3334
assetAmount uint64
3435
bidPrice lnwire.MilliSatoshi
3536
}{
37+
{
38+
testName: "asset group key nil, version 0",
39+
version: 0,
40+
id: id,
41+
assetId: &assetId,
42+
assetGroupKey: nil,
43+
assetAmount: 1000,
44+
bidPrice: lnwire.MilliSatoshi(42000),
45+
},
3646
{
3747
testName: "asset group key nil",
48+
version: 5,
3849
id: id,
3950
assetId: &assetId,
4051
assetGroupKey: nil,
@@ -46,6 +57,7 @@ func TestBuyRequestMsgDataEncodeDecode(t *testing.T) {
4657
for _, tc := range testCases {
4758
t.Run(tc.testName, func(tt *testing.T) {
4859
req := buyRequestMsgData{
60+
Version: tc.version,
4961
ID: tc.id,
5062
AssetID: tc.assetId,
5163
AssetGroupKey: tc.assetGroupKey,

rfqmsg/messages.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/binary"
66
"encoding/hex"
77
"errors"
8+
"io"
89
"math"
910

1011
"github.com/lightningnetwork/lnd/lnwire"
@@ -115,6 +116,45 @@ func NewIncomingMsgFromWire(wireMsg WireMessage) (IncomingMsg, error) {
115116
}
116117
}
117118

119+
// WireMsgDataVersion specifies the version of the contents within a wire
120+
// message data field.
121+
type WireMsgDataVersion uint8
122+
123+
const (
124+
// V0 represents version 0 of the contents in a wire message data field.
125+
V0 WireMsgDataVersion = 0
126+
)
127+
128+
// WireMsgDataVersionEncoder is a function that can be used to encode a
129+
// WireMsgDataVersion to a writer.
130+
func WireMsgDataVersionEncoder(w io.Writer, val any, buf *[8]byte) error {
131+
if version, ok := val.(*WireMsgDataVersion); ok {
132+
versionUint8 := uint8(*version)
133+
return tlv.EUint8(w, &versionUint8, buf)
134+
}
135+
136+
return tlv.NewTypeForEncodingErr(val, "WireMsgDataVersion")
137+
}
138+
139+
// WireMsgDataVersionDecoder is a function that can be used to decode a
140+
// WireMsgDataVersion from a reader.
141+
func WireMsgDataVersionDecoder(r io.Reader, val any, buf *[8]byte,
142+
l uint64) error {
143+
144+
if version, ok := val.(*WireMsgDataVersion); ok {
145+
var versionInt uint8
146+
err := tlv.DUint8(r, &versionInt, buf, l)
147+
if err != nil {
148+
return err
149+
}
150+
151+
*version = WireMsgDataVersion(versionInt)
152+
return nil
153+
}
154+
155+
return tlv.NewTypeForDecodingErr(val, "WireMsgDataVersion", l, 8)
156+
}
157+
118158
// IncomingMsg is an interface that represents an inbound wire message
119159
// that has been received from a peer.
120160
type IncomingMsg interface {

rfqmsg/reject.go

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,21 @@ import (
1212
const (
1313
// Reject message type field TLV types.
1414

15-
TypeRejectID tlv.Type = 0
16-
TypeRejectErrCode tlv.Type = 1
17-
TypeRejectErrMsg tlv.Type = 3
15+
TypeRejectVersion tlv.Type = 0
16+
TypeRejectID tlv.Type = 2
17+
TypeRejectErrCode tlv.Type = 3
18+
TypeRejectErrMsg tlv.Type = 5
1819
)
1920

21+
func TypeRecordRejectVersion(version *WireMsgDataVersion) tlv.Record {
22+
const recordSize = 1
23+
24+
return tlv.MakeStaticRecord(
25+
TypeRejectVersion, version, recordSize,
26+
WireMsgDataVersionEncoder, WireMsgDataVersionDecoder,
27+
)
28+
}
29+
2030
func TypeRecordRejectID(id *ID) tlv.Record {
2131
const recordSize = 32
2232

@@ -102,9 +112,18 @@ var (
102112
}
103113
)
104114

115+
const (
116+
// latestRejectVersion is the latest supported reject wire message data
117+
// field version.
118+
latestRejectVersion = V0
119+
)
120+
105121
// rejectMsgData is a struct that represents the data field of a quote
106122
// reject message.
107123
type rejectMsgData struct {
124+
// Version is the version of the message data.
125+
Version WireMsgDataVersion
126+
108127
// ID represents the unique identifier of the quote request message that
109128
// this response is associated with.
110129
ID ID
@@ -118,6 +137,7 @@ type rejectMsgData struct {
118137
// runtime.
119138
func (q *rejectMsgData) encodeRecords() []tlv.Record {
120139
return []tlv.Record{
140+
TypeRecordRejectVersion(&q.Version),
121141
TypeRecordRejectID(&q.ID),
122142
TypeRecordRejectErrCode(&q.Err.Code),
123143
TypeRecordRejectErrMsg(&q.Err.Msg),
@@ -136,6 +156,7 @@ func (q *rejectMsgData) Encode(writer io.Writer) error {
136156
// DecodeRecords provides all TLV records for decoding.
137157
func (q *rejectMsgData) decodeRecords() []tlv.Record {
138158
return []tlv.Record{
159+
TypeRecordRejectVersion(&q.Version),
139160
TypeRecordRejectID(&q.ID),
140161
TypeRecordRejectErrCode(&q.Err.Code),
141162
TypeRecordRejectErrMsg(&q.Err.Msg),
@@ -178,8 +199,9 @@ func NewReject(peer route.Vertex, requestId ID,
178199
return &Reject{
179200
Peer: peer,
180201
rejectMsgData: rejectMsgData{
181-
ID: requestId,
182-
Err: rejectErr,
202+
Version: latestRejectVersion,
203+
ID: requestId,
204+
Err: rejectErr,
183205
},
184206
}
185207
}
@@ -200,6 +222,12 @@ func NewQuoteRejectFromWireMsg(wireMsg WireMessage) (*Reject, error) {
200222
"message data: %w", err)
201223
}
202224

225+
// Ensure that the message version is supported.
226+
if msgData.Version > latestRejectVersion {
227+
return nil, fmt.Errorf("unsupported reject message version: %d",
228+
msgData.Version)
229+
}
230+
203231
return &Reject{
204232
Peer: wireMsg.Peer,
205233
rejectMsgData: msgData,

rfqmsg/reject_test.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,23 @@ func TestRejectEncodeDecode(t *testing.T) {
2020
testCases := []struct {
2121
testName string
2222

23-
peer route.Vertex
24-
id ID
25-
err RejectErr
23+
peer route.Vertex
24+
version WireMsgDataVersion
25+
id ID
26+
err RejectErr
2627
}{
28+
{
29+
testName: "all fields populated with basic values, " +
30+
"zero version",
31+
peer: route.Vertex{1, 2, 3},
32+
version: 0,
33+
id: id,
34+
err: ErrNoSuitableBuyOffer,
35+
},
2736
{
2837
testName: "all fields populated with basic values",
2938
peer: route.Vertex{1, 2, 3},
39+
version: 5,
3040
id: id,
3141
err: ErrNoSuitableBuyOffer,
3242
},

0 commit comments

Comments
 (0)