Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
ffranr committed Jan 22, 2024
1 parent c621cfb commit ee71fb0
Show file tree
Hide file tree
Showing 7 changed files with 277 additions and 167 deletions.
20 changes: 7 additions & 13 deletions itest/rfq.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package itest

import (
"bytes"
"math/rand"
"time"

"github.com/lightninglabs/taproot-assets/internal/test"
"github.com/lightninglabs/taproot-assets/rfqmessages"
rfqmsg "github.com/lightninglabs/taproot-assets/rfqmessages"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/stretchr/testify/require"
)
Expand All @@ -28,26 +27,21 @@ func testQuoteRequest(t *harnessTest) {
// Generate a random asset group key.
randomGroupPrivateKey := test.RandPrivKey(t.t)

quoteRequest := rfqmessages.QuoteRequest{
ID: randomQuoteRequestId,
//AssetID: &randomAssetId,
AssetGroupKey: randomGroupPrivateKey.PubKey(),
AssetAmount: 42,
SuggestedRateTick: 10,
}
quoteRequestMsgData, err := rfqmsg.NewQuoteRequestMsgData(

Check failure on line 30 in itest/rfq.go

View workflow job for this annotation

GitHub Actions / Lint check

ineffectual assignment to err (ineffassign)
randomQuoteRequestId, nil, randomGroupPrivateKey.PubKey(), 42,
10,
)

// TLV encode the quote request.
var streamBuf bytes.Buffer
err = quoteRequest.Encode(&streamBuf)
quoteReqBytes, err := quoteRequestMsgData.Bytes()
require.NoError(t.t, err, "unable to encode quote request")
quoteReqBytes := streamBuf.Bytes()

resAlice := t.lndHarness.Alice.RPC.GetInfo()
t.Logf("Sending custom message to alias: %s", resAlice.Alias)

t.lndHarness.Bob.RPC.SendCustomMessage(&lnrpc.SendCustomMessageRequest{
Peer: t.lndHarness.Alice.PubKey[:],
Type: rfqmessages.MsgTypeQuoteRequest,
Type: rfqmsg.MsgTypeQuoteRequest,
Data: quoteReqBytes,
})

Expand Down
7 changes: 6 additions & 1 deletion rfqmessages/messages.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package rfqmessages

import "github.com/lightningnetwork/lnd/lnwire"
import (
"github.com/lightningnetwork/lnd/lnwire"
)

// ID is the identifier for a RFQ message.
type ID [32]byte

// TapMessageTypeBaseOffset is the taproot-assets specific message type
// identifier base offset. All tap messages will have a type identifier that is
Expand Down
192 changes: 111 additions & 81 deletions rfqmessages/req_accept.go
Original file line number Diff line number Diff line change
@@ -1,144 +1,174 @@
package rfqmessages

import (
"crypto/sha256"
"bytes"
"fmt"
"io"

"github.com/btcsuite/btcd/btcec/v2"
"github.com/lightninglabs/taproot-assets/asset"
"github.com/lightninglabs/lndclient"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/tlv"
)

const (
// QuoteAccept field TLV types.
// QuoteAcceptMsgData field TLV types.

QuoteAcceptIDType tlv.Type = 0
QuoteAcceptAssetIDType tlv.Type = 1
QuoteAcceptGroupKeyType tlv.Type = 3
QuoteAcceptAssetAmountType tlv.Type = 4
QuoteAcceptAmtCharacteristicType tlv.Type = 6
QuoteAcceptMsgDataIDType tlv.Type = 0
QuoteAcceptMsgDataCharacteristicType tlv.Type = 2
QuoteAcceptMsgDataExpiryType tlv.Type = 4
QuoteAcceptMsgDataSignatureType tlv.Type = 6
)

func QuoteAcceptIDRecord(id *[32]byte) tlv.Record {
return tlv.MakePrimitiveRecord(QuoteAcceptIDType, id)
func QuoteAcceptMsgDataIDRecord(id *ID) tlv.Record {
return tlv.MakePrimitiveRecord(QuoteAcceptMsgDataIDType, id)
}

func QuoteAcceptAssetIDRecord(assetID **asset.ID) tlv.Record {
const recordSize = sha256.Size

return tlv.MakeStaticRecord(
QuoteAcceptAssetIDType, assetID, recordSize,
IDEncoder, IDDecoder,
func QuoteAcceptMsgDataCharacteristicRecord(characteristic *uint64) tlv.Record {
return tlv.MakePrimitiveRecord(
QuoteAcceptMsgDataCharacteristicType, characteristic,
)
}

func QuoteAcceptGroupKeyRecord(groupKey **btcec.PublicKey) tlv.Record {
const recordSize = btcec.PubKeyBytesLenCompressed

return tlv.MakeStaticRecord(
QuoteAcceptGroupKeyType, groupKey, recordSize,
asset.CompressedPubKeyEncoder, asset.CompressedPubKeyDecoder,
func QuoteAcceptMsgDataExpiryRecord(expirySeconds *uint64) tlv.Record {
return tlv.MakePrimitiveRecord(
QuoteAcceptMsgDataExpiryType, expirySeconds,
)
}

func QuoteAcceptAssetAmountRecord(assetAmount *uint64) tlv.Record {
return tlv.MakePrimitiveRecord(QuoteAcceptAssetAmountType, assetAmount)
}

func QuoteAcceptAmtCharacteristicRecord(amtCharacteristic *uint64) tlv.Record {
func QuoteAcceptMsgDataSig(sig *[64]byte) tlv.Record {
return tlv.MakePrimitiveRecord(
QuoteAcceptAmtCharacteristicType, amtCharacteristic,
QuoteAcceptMsgDataSignatureType, sig,
)
}

// QuoteAccept is a struct that represents a request for a quote (RFQ) from a
// QuoteAcceptMsgData is a struct that represents a request for a quote (RFQ) from a
// peer.
type QuoteAccept struct {
type QuoteAcceptMsgData struct {
// ID is the unique identifier of the request for quote (RFQ).
ID [32]byte

// // AssetID represents the identifier of the asset for which the peer
// is requesting a quote.
AssetID *asset.ID
ID ID

// AssetGroupKey is the public group key of the asset for which the peer
// is requesting a quote.
AssetGroupKey *btcec.PublicKey
// AmtCharacteristic is the characteristic of the asset amount that
// determines the fee rate.
AmtCharacteristic uint64

// AssetAmount is the amount of the asset for which the peer is
// requesting a quote.
AssetAmount uint64
// ExpirySeconds is the number of seconds until the quote expires.
ExpirySeconds uint64

// TODO(ffranr): rename to AmtCharacteristic?
SuggestedRateTick uint64
// Sig is a signature over the serialized contents of the message.
Sig [64]byte
}

// Validate ensures that the quote request is valid.
func (q *QuoteAccept) Validate() error {
if q.AssetID == nil && q.AssetGroupKey == nil {
return fmt.Errorf("asset id and group key cannot both be nil")
}

if q.AssetID != nil && q.AssetGroupKey != nil {
return fmt.Errorf("asset id and group key cannot both be " +
"non-nil")
}

return nil
}
//func NewQuoteAcceptMsgData(q *QuoteAccept) (*QuoteAcceptMsgData, error) {
// // Hash the fields of the message data so that we can create a signature
// // over the message.
// h := sha256.New()
//
// _, err := h.Write(q.ID[:])
// if err != nil {
// return nil, err
// }
//
// err = binary.Write(h, binary.BigEndian, q.AmtCharacteristic)
// if err != nil {
// return nil, err
// }
//
// err = binary.Write(h, binary.BigEndian, q.ExpirySeconds)
// if err != nil {
// return nil, err
// }
//
// // TODO(ffranr): Sign the hash of the message data.
// //fieldsHash := h.Sum(nil)
// //sig
//
// return &QuoteAcceptMsgData{
// ID: q.ID,
// AmtCharacteristic: q.AmtCharacteristic,
// ExpirySeconds: q.ExpirySeconds,
// //Sig: sig,
// }, nil
//}

// EncodeRecords determines the non-nil records to include when encoding an
// asset witness at runtime.
func (q *QuoteAccept) EncodeRecords() []tlv.Record {
func (q *QuoteAcceptMsgData) encodeRecords() []tlv.Record {
var records []tlv.Record

records = append(records, QuoteAcceptIDRecord(&q.ID))

if q.AssetID != nil {
records = append(records, QuoteAcceptAssetIDRecord(&q.AssetID))
}
// Add ID record.
records = append(records, QuoteAcceptMsgDataIDRecord(&q.ID))

if q.AssetGroupKey != nil {
record := QuoteAcceptGroupKeyRecord(&q.AssetGroupKey)
records = append(records, record)
}
// Add characteristic record.
record := QuoteAcceptMsgDataCharacteristicRecord(
&q.AmtCharacteristic,
)
records = append(records, record)

records = append(records, QuoteAcceptAssetAmountRecord(&q.AssetAmount))
// Add expiry record.
records = append(
records, QuoteAcceptMsgDataExpiryRecord(&q.ExpirySeconds),
)

record := QuoteAcceptAmtCharacteristicRecord(&q.SuggestedRateTick)
records = append(records, record)
// Add signature record.
records = append(
records, QuoteAcceptMsgDataSig(&q.Sig),
)

return records
}

// Encode encodes the structure into a TLV stream.
func (q *QuoteAccept) Encode(writer io.Writer) error {
stream, err := tlv.NewStream(q.EncodeRecords()...)
func (q *QuoteAcceptMsgData) Encode(writer io.Writer) error {
stream, err := tlv.NewStream(q.encodeRecords()...)
if err != nil {
return err
}
return stream.Encode(writer)
}

// DecodeRecords provides all TLV records for decoding.
func (q *QuoteAccept) DecodeRecords() []tlv.Record {
func (q *QuoteAcceptMsgData) decodeRecords() []tlv.Record {
return []tlv.Record{
QuoteAcceptIDRecord(&q.ID),
QuoteAcceptAssetIDRecord(&q.AssetID),
QuoteAcceptGroupKeyRecord(&q.AssetGroupKey),
QuoteAcceptAssetAmountRecord(&q.AssetAmount),
QuoteAcceptAmtCharacteristicRecord(&q.SuggestedRateTick),
QuoteAcceptMsgDataIDRecord(&q.ID),
QuoteAcceptMsgDataCharacteristicRecord(&q.AmtCharacteristic),
QuoteAcceptMsgDataExpiryRecord(&q.ExpirySeconds),
QuoteAcceptMsgDataSig(&q.Sig),
}
}

// Decode decodes the structure from a TLV stream.
func (q *QuoteAccept) Decode(r io.Reader) error {
stream, err := tlv.NewStream(q.DecodeRecords()...)
func (q *QuoteAcceptMsgData) Decode(r io.Reader) error {
stream, err := tlv.NewStream(q.decodeRecords()...)
if err != nil {
return err
}
return stream.Decode(r)
}

//func EncodeAsPeerMsg()
// QuoteAccept is a struct that represents an accepted quote message.
type QuoteAccept struct {
// Peer is the peer that sent the quote request.
Peer route.Vertex

// QuoteAcceptMsgData is the message data from the quote accept message.
QuoteAcceptMsgData
}

// LndCustomMsg returns a custom message that can be sent to a peer using the
// lndclient.
func (q *QuoteAccept) LndCustomMsg() (*lndclient.CustomMessage, error) {
// Encode message data component as TLV bytes.
var buff *bytes.Buffer
err := q.QuoteAcceptMsgData.Encode(buff)
if err != nil {
return nil, fmt.Errorf("unable to encode quote accept "+
"message data: %w", err)
}
quoteAcceptBytes := buff.Bytes()

return &lndclient.CustomMessage{
Peer: q.Peer,
MsgType: MsgTypeQuoteAccept,
Data: quoteAcceptBytes,
}, nil
}
Loading

0 comments on commit ee71fb0

Please sign in to comment.