-
Notifications
You must be signed in to change notification settings - Fork 130
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
Multi rfq receive (AddInvoice
multiple hop hints)
#1457
base: main
Are you sure you want to change the base?
Conversation
We add a new interface to the HTLC SumAssetBalance method, which helps check the identifier of the asset against a specifier. This allows for checking asset inclusion in a group, which is a bit involved and not the responsibility of the HTLC model.
We extend the interface of the rfq Policy in order to allow the specifier checker to be involved. This extends certain checks, and allows us to use asset specifiers that only have a group key.
When intercepting an HTLC which is incoming from a btc channel and outgoing towards an asset channel, we need to create an HTLC record which reflects the asset related balance change. What really matter in these records is the total asset amount, but we also set the assetID field to be either equal to the specific asset we're sending, or the group of assets. This field does not dictate what the actual assets being sent are going to be, that will be decided later in the asset allocation process.
This allows us to get rid of a circular dependency issue that would occur in a follow up commit, where we import the adress package in the rfq package. Co-authored-by: Oliver Gugger <[email protected]>
We add the specifier checker interface to the AuxInvoiceManager too, as it is needed to validate incoming HTLCs which may use asset IDs that belong to a group, while the RFQ is based on a group key.
Adds some coverage to the invoice manager unit tests, which involve an RFQ quote over a group key, plus an HTLC with multiple asset balances, which may belong or not to the group.
We may be performing a group lookup on an asset that doesn't belong to a group. Instead of returning the error that originates from the ErrNoRows of sql we instead return a nil result, signalling that no group was found and no error occurred.
In some cases the sender of an asset HTLC may just encode the hash of the group key as the assetID of the balance in the custom records. This is done as a way to signal that any asset ID that belongs to this group may be picked to carry out the payment. This commit makes the specifier matcher aware of that case.
As mentioned in the previous commit, we occasionally want to just encode the hash of the group key as the asset ID of the balance that is encoded in the custom record. We make the ProduceHtlcExtraData hook aware of that case, which is triggered when the quote is made upon a group key and not a specific asset ID.
We have taken care of the groupkey RFQ negotiation in previous commits. All we need now to support sending a payment over a group of assets, is to propagate the user specifier groupkey to the corresponding fields.
In this commit we take the user defined group key and allow the asset specifier to be created over it. All the calls that accept it as an argument are already groupkey aware.
99e85a7
to
e2e8e47
Compare
@@ -6432,6 +6432,31 @@ func MarshalAssetFedSyncCfg( | |||
}, nil | |||
} | |||
|
|||
// marshalAssetSpecifier marshals an asset specifier to the RPC form. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we don't allow the combo here? Of group key and an asset ID.
} | ||
|
||
if pass { | ||
// Since the assets of the channel passed the above |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -1066,9 +1067,11 @@ type ChannelWithSpecifier struct { | |||
// each asset channel that matches the provided asset specifier. | |||
func (m *Manager) ComputeChannelAssetBalance(ctx context.Context, | |||
activeChannels []lndclient.ChannelInfo, | |||
specifier asset.Specifier) ([]ChannelWithSpecifier, error) { | |||
specifier asset.Specifier) (map[route.Vertex][]ChannelWithSpecifier, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style nit: can use a type def here to give the data structure a more descriptive name/type, and also cut down on the amt of chars needed to ref it a bit.
acceptedQuote.AskAssetRate) | ||
} | ||
// Let's sort the ask rate of the quotes in ascending order. | ||
sort.Slice(acquiredQuotes, func(i, j int) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Solid initial strategy.
In the future, we'll also want to take into account what the allotted amount of volume is. For now, since we basically never have standing orders (we req just enough to recv), this isn't strictly required.
// invoice amount. Since peers have varying prices for the assets, we | ||
// pick the most expensive rate in order to allow for any combination of | ||
// MPP shards through our set of chosen peers. | ||
expensiveRate := acquiredQuotes[0].rate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why should we pick the most expensive quote? This is effectively the same as giving the sender an option for the most expensive route in terms of fees.
|
||
// Convert the asset amount into a fixed-point. | ||
assetAmount := rfqmath.NewBigIntFixedPoint(req.AssetAmount, 0) | ||
|
||
// Calculate the invoice amount in msat. | ||
valMsat := rfqmath.UnitsToMilliSatoshi(assetAmount, *askAssetRate) | ||
valMsat := rfqmath.UnitsToMilliSatoshi(assetAmount, *expensiveRate) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah ok, I think this is making a bit more sense now: ultimately we need to put some value into the invoice. I think we'll want to do another level of filtering here to ensure that we don't force the user to overpay. Or will the acceptance deviation check handle that?
{ | ||
routeHints := make([]*lnrpc.RouteHint, 0) | ||
for _, v := range acquiredQuotes { | ||
hopHint, _, err := r.cfg.RfqManager.RfqToHopHint( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
} | ||
iReq.RouteHints = []*lnrpc.RouteHint{ | ||
{ | ||
routeHints := make([]*lnrpc.RouteHint, 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here re var vs make.
e2e8e47
to
e9e1de8
Compare
@GeorgeTsagk, remember to re-request review from reviewers when ready |
Description
This PR introduces the ability for tapd nodes to create invoices which involve multiple peer quotes. When the
peerPubKey
is left unspecified in theAddInvoice
RPC we no longer return an error, but instead acquire quotes with all peers that have a valid asset channel with us.Within this PR we also extract some rfq/liquidity related functions to the
rfq
package to keeprpcserver.go
more clean.Closes #1359
Based on #1423 (using that as base branch for now to avoid bloated diff)