-
Notifications
You must be signed in to change notification settings - Fork 121
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
Invoice Acceptor: ensure asset ID match between RFQ and HTLC #1299
base: main
Are you sure you want to change the base?
Invoice Acceptor: ensure asset ID match between RFQ and HTLC #1299
Conversation
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.
Good idea!
tapchannel/aux_invoice_manager.go
Outdated
|
||
assetID := s.assetIDFromQuote(rfqID) | ||
for _, v := range htlc.Balances() { | ||
if v.AssetID.Val != *assetID { |
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.
To avoid dereference of nil at *assetID
I think assetIDFromQuote
should return asset.ID, error
(error in case of missing policy for HTLC).
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.
This is unaddressed. By returning the identifier directly, we can do if !ident.HasId() {
.
TODO
|
ef54607
to
5e76383
Compare
Pull Request Test Coverage Report for Build 12906816979Details
💛 - Coveralls |
5e76383
to
5b235ef
Compare
@@ -422,6 +431,42 @@ func TestAuxInvoiceManager(t *testing.T) { | |||
}, | |||
}, | |||
}, | |||
{ | |||
name: "asset invoice, wrong asset htlc", |
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.
Added coverage for this in our unit test cases
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.
Careful self review of the commits would've prevented 50-60% of my comments...
Approach looks okay to me but can be perhaps made a bit more generic.
tapchannel/aux_invoice_manager.go
Outdated
|
||
assetID := s.assetIDFromQuote(rfqID) | ||
for _, v := range htlc.Balances() { | ||
if v.AssetID.Val != *assetID { |
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.
This is unaddressed. By returning the identifier directly, we can do if !ident.HasId() {
.
We add a simple identifierFromQuote function that fetches the asset specifier associated with a certain accepted quote identified by its rfq ID. We will later use this in the handleInvoice function to compare the identifier of the quote with that of the HTLCs.
5b235ef
to
6066385
Compare
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.
Nice! This is pretty much there IMO.
I'm just going to suggest a potential simplification in this review.
In this commit we utilize the previously defined helper in order to define a new htlc validation function. The validation currently includes checking that the asset ID of the rfq and the HTLCs always match. This is done as an extra strict check to guard against HTLC and RFQ asset specifier mismatch, which can lead to malicious behavior where a quote for a different asset is being accounted for when accepting an asset HTLC.
For test cases where an RFQ does not exist we fail earlier, so we need to update the expected behavior on the tests. We also need to be more strict when creating dummy RFQs, as now the request with the asset specifier needs to be present, for the new checks to take place.
6066385
to
845e0f6
Compare
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.
Looks good. One more suggestion, but non-blocking.
if !identifier.HasId() { | ||
return fmt.Errorf("asset specifier has empty assetID") | ||
} |
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.
This can be moved to before the loop.
if v.AssetID.Val != *identifier.UnwrapIdToPtr() { | ||
return fmt.Errorf("mismatch between htlc asset ID " + | ||
"and rfq asset ID") | ||
} |
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.
This feels very much against the whole Option
paradigm... We could add an ID()
or IDOption()
method to the specifier that returns the underlying fn.Option
directly, then we could do this the "intended" way:
err := fn.MapOptionZ(
identifier.IdOption(), func(id asset.ID) error {
if v.AssetID.Val != id {
return fmt.Errorf("mismatch between " +
"htlc asset ID and rfq asset " +
"ID")
}
return nil
},
)
if err != nil {
return err
}
But non-blocking.
Description
This PR adds an extra strictness check which requires the asset ID of the RFQ quote and HTLC records to match. This is done as an extra strict check to guard against HTLC and RFQ asset ID mismatch, which can lead to malicious behavior where a quote for a different asset is being accounted for when accepting an asset HTLC.
Closes #1255