Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tapchannel: add new AuxChanCloser to enable co-op close for asset channels #919

Merged
merged 16 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions perms/perms.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,10 @@ var (
Entity: "channels",
Action: "write",
}},
"/tapchannelrpc.TaprootAssetChannels/EncodeCustomRecords": {
// This RPC is completely stateless and doesn't require
// any permissions to use.
},
"/tapdevrpc.TapDev/ImportProof": {{
Entity: "proofs",
Action: "write",
Expand Down
76 changes: 76 additions & 0 deletions rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import (
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/signal"
"github.com/lightningnetwork/lnd/tlv"
"golang.org/x/exp/maps"
"golang.org/x/time/rate"
"google.golang.org/grpc"
Expand Down Expand Up @@ -6441,6 +6442,81 @@ func (r *rpcServer) FundChannel(ctx context.Context,
}, nil
}

// EncodeCustomRecords allows RPC users to encode Taproot Asset channel related
// data into the TLV format that is used in the custom records of the lnd
// payment or other channel related RPCs. This RPC is completely stateless and
// does not perform any checks on the data provided, other than pure format
// validation.
func (r *rpcServer) EncodeCustomRecords(_ context.Context,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still this as something that's temp? As in we'd just wrap the payment specific stuff in an entirely new RPC?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so, yes. Or maybe not, given that with this it should be pretty easy to do the RPC calls in any language. I guess the question is: how much effort is it for the app devs to call 3 RPCs (buy/sell order, encode records, send payment) with the correct values vs. us threading all the payment and channel flags through some new RPC methods in tapd...

in *tchrpc.EncodeCustomRecordsRequest) (
*tchrpc.EncodeCustomRecordsResponse, error) {

switch i := in.Input.(type) {
case *tchrpc.EncodeCustomRecordsRequest_RouterSendPayment:
req := i.RouterSendPayment

assetAmounts := make(
[]*rfqmsg.AssetBalance, 0, len(req.AssetAmounts),
)
for idStr, amount := range req.AssetAmounts {
idBytes, err := hex.DecodeString(idStr)
if err != nil {
return nil, fmt.Errorf("error decoding asset "+
"ID: %w", err)
}

if len(idBytes) != sha256.Size {
return nil, fmt.Errorf("asset ID must be 32 " +
"bytes")
}

if amount == 0 {
return nil, fmt.Errorf("asset amount must be " +
"specified")
}

var assetID asset.ID
copy(assetID[:], idBytes)

assetAmounts = append(
assetAmounts, rfqmsg.NewAssetBalance(
assetID, amount,
),
)
}

rfqID := fn.None[rfqmsg.ID]()
if len(req.RfqId) > 0 {
if len(req.RfqId) != sha256.Size {
return nil, fmt.Errorf("RFQ ID must be empty " +
"or exactly 32 bytes")
}

var id rfqmsg.ID
copy(id[:], req.RfqId)

rfqID = fn.Some[rfqmsg.ID](id)
}

htlc := rfqmsg.NewHtlc(assetAmounts, rfqID)

// We'll now map the HTLC struct into a set of TLV records,
// which we can then encode into the map format expected.
htlcMapRecords, err := tlv.RecordsToMap(htlc.Records())
if err != nil {
return nil, fmt.Errorf("unable to encode records as "+
"map: %w", err)
}

return &tchrpc.EncodeCustomRecordsResponse{
CustomRecords: htlcMapRecords,
}, nil

default:
return nil, fmt.Errorf("unknown input type: %T", i)
}
}

// serialize is a helper function that serializes a serializable object into a
// byte slice.
func serialize(s interface{ Serialize(io.Writer) error }) ([]byte, error) {
Expand Down
Loading