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

imp(fee): capital efficient fee middleware #5571

Merged
merged 23 commits into from
Jan 17, 2024

Conversation

srdtrk
Copy link
Member

@srdtrk srdtrk commented Jan 10, 2024

Description

closes: #5509

Commit Message / Changelog Entry

imp(fee): capital efficient fee middleware

see the guidelines for commit messages. (view raw markdown for examples)


Before we can merge this PR, please make sure that all the following items have been
checked off. If any of the checklist items are not applicable, please leave them but
write a little note why.

  • Targeted PR against the correct branch (see CONTRIBUTING.md).
  • Linked to Github issue with discussion and accepted design OR link to spec that describes this work.
  • Code follows the module structure standards and Go style guide.
  • Wrote unit and integration tests.
  • Updated relevant documentation (docs/) or specification (x/<module>/spec/).
  • Added relevant godoc comments.
  • Provide a commit message to be used for the changelog entry in the PR description for review.
  • Re-reviewed Files changed in the Github PR explorer.
  • Review Codecov Report in the comment section below once CI passes.

@srdtrk srdtrk added 29-fee change: state machine breaking Issues or PRs that break consensus (need to be released in at least a new minor version) labels Jan 10, 2024
@codecov-commenter
Copy link

codecov-commenter commented Jan 10, 2024

Codecov Report

Attention: 2 lines in your changes are missing coverage. Please review.

Comparison is base (f3c76cd) 81.22% compared to head (c689769) 81.19%.
Report is 2 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #5571      +/-   ##
==========================================
- Coverage   81.22%   81.19%   -0.04%     
==========================================
  Files         197      198       +1     
  Lines       15258    15284      +26     
==========================================
+ Hits        12394    12410      +16     
- Misses       2399     2406       +7     
- Partials      465      468       +3     
Files Coverage Δ
modules/apps/29-fee/keeper/escrow.go 92.76% <100.00%> (-0.05%) ⬇️
modules/apps/29-fee/keeper/migrations.go 100.00% <100.00%> (ø)
modules/apps/29-fee/types/fee.go 82.35% <100.00%> (+0.35%) ⬆️
modules/apps/29-fee/module.go 48.93% <60.00%> (+0.09%) ⬆️

... and 1 file with indirect coverage changes

@srdtrk srdtrk marked this pull request as ready for review January 11, 2024 07:47
@crodriguezvega crodriguezvega added priority PRs that need prompt reviews backport-to-v8.1.x labels Jan 11, 2024
Copy link
Contributor

@charleenfei charleenfei left a comment

Choose a reason for hiding this comment

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

generally lgtm! just a few small nits about testing/godocs/inline docs

"success: some refund amount",
func() {
// set the recv + ack fee to be greater than timeout fee so that the refund amount is non-zero
fee = types.NewFee(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(200))), defaultAckFee, defaultTimeoutFee)
Copy link
Contributor

Choose a reason for hiding this comment

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

do we need a new fee testing var here? can't we just use continue using packetFee and a const for fee?

Copy link
Member Author

Choose a reason for hiding this comment

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

It was defined previously. I didn't wanna remove it and break tests.

@@ -65,7 +65,7 @@ func (suite *FeeTestSuite) TestFeeTransfer() {
)

suite.Require().Equal(
fee.AckFee.Add(fee.TimeoutFee...), // ack fee paid, timeout fee refunded
fee.AckFee, // ack fee paid, no refund needed since timeout_fee = recv_fee + ack_fee
Copy link
Contributor

Choose a reason for hiding this comment

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

i find this comment slightly confusing, it's more that the timeout fee wasn't escrowed since it was smaller than the recv+ack, correct?

Copy link
Member Author

Choose a reason for hiding this comment

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

In this case, there is equality due to hard-coded values

@@ -60,8 +60,10 @@ func NewFee(recvFee, ackFee, timeoutFee sdk.Coins) Fee {
}

// Total returns the total amount for a given Fee
// The total amount is the Max(TimeoutFee, AckFee + RecvFee)
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe just a bit more explicit that only the max of these two will actually be escrowed?

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe also indicate the reasoning for this decision (to efficiently escrow capital)?

Copy link
Contributor

@colin-axner colin-axner left a comment

Choose a reason for hiding this comment

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

Superb work! I'm very happy with how few diffs there are for non test code! I think it'd be nice if we added some documentation for this behaviour? Maybe a quick section on the main docs? Feels like a behaviour that would be useful for users to find out about

modules/apps/29-fee/keeper/escrow.go Outdated Show resolved Hide resolved
modules/apps/29-fee/keeper/escrow.go Outdated Show resolved Hide resolved
modules/apps/29-fee/ibc_middleware_test.go Outdated Show resolved Hide resolved
modules/apps/29-fee/keeper/escrow_test.go Outdated Show resolved Hide resolved
modules/apps/29-fee/keeper/escrow_test.go Outdated Show resolved Hide resolved
modules/apps/29-fee/keeper/escrow_test.go Show resolved Hide resolved
modules/apps/29-fee/keeper/escrow_test.go Outdated Show resolved Hide resolved
modules/apps/29-fee/keeper/escrow_test.go Outdated Show resolved Hide resolved
@@ -60,8 +60,10 @@ func NewFee(recvFee, ackFee, timeoutFee sdk.Coins) Fee {
}

// Total returns the total amount for a given Fee
// The total amount is the Max(TimeoutFee, AckFee + RecvFee)
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe also indicate the reasoning for this decision (to efficiently escrow capital)?

modules/apps/29-fee/types/fee.go Show resolved Hide resolved
Copy link
Member

@AdityaSripal AdityaSripal left a comment

Choose a reason for hiding this comment

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

Great work!! I noticed the tests on refund are doing exactly the same logic as the distribution logic.

While this is correct, if for whatever reason the functions are not doing what we expected them to do, we won't catch it. Effectively, I don't think we're testing anything real since we're checking if assert(Z - A - B = Z - A - B)

I think I'd be a bit more confident, if you hardcoded the expected refund amount in the tests, at least where you are explicitly trying to assert refund logic is correct.
So something more like assert(Z - A - B = 15)

Everything else looks great, approved after that

modules/apps/29-fee/types/fee.go Show resolved Hide resolved
@AdityaSripal
Copy link
Member

Also, if the fees are all in one-denom, then we should definitely have tests that the multi-denom case works as we expect

@colin-axner colin-axner self-requested a review January 11, 2024 18:05
modules/apps/29-fee/ibc_middleware_test.go Outdated Show resolved Hide resolved
modules/apps/29-fee/ibc_middleware_test.go Outdated Show resolved Hide resolved
modules/apps/29-fee/keeper/escrow_test.go Outdated Show resolved Hide resolved
modules/apps/29-fee/keeper/escrow_test.go Outdated Show resolved Hide resolved
modules/apps/29-fee/keeper/escrow_test.go Outdated Show resolved Hide resolved
modules/apps/29-fee/keeper/escrow_test.go Outdated Show resolved Hide resolved
@srdtrk srdtrk marked this pull request as draft January 15, 2024 14:13
@srdtrk srdtrk marked this pull request as ready for review January 15, 2024 17:03
@srdtrk
Copy link
Member Author

srdtrk commented Jan 15, 2024

@colin-axner and @crodriguezvega, I will open a separate issue and PR for docs, since this PR is time sensitive and should not be blocked on documentation nits

Copy link
Member

@AdityaSripal AdityaSripal left a comment

Choose a reason for hiding this comment

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

Migration logic looks good! still have my point about tests. happy to defer to team on this

bump: #5571 (review)

@srdtrk
Copy link
Member Author

srdtrk commented Jan 16, 2024

@AdityaSripal I think the tests have a healthy mix of hard-coded (like defaultFees) and computed values. If all values were hard-coded, it'd have been a nightmare to update tests.

Also, the current state of tests reflects the state of tests before the PR. I think such a refactor should be a separate issue if others agree to it

Copy link
Member

@damiannolan damiannolan left a comment

Choose a reason for hiding this comment

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

Code looks great, making my way through the tests. Figured I share this initial comment on the fee Total() func

modules/apps/29-fee/types/fee.go Show resolved Hide resolved
Copy link
Member

@damiannolan damiannolan left a comment

Choose a reason for hiding this comment

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

Awesome work @srdtrk! I think I've finished looking through all the tests. Migration code looks great. We should wire up an upgrade handler and add an e2e test in a follow up.

I share the same feeling as @AdityaSripal wrt to hardcoding expected values in tests, might make them easier to parse!

// check if the refund acc has been refunded the timeoutFee & recvFee
expectedRefundAccBal := refundAccBal.Add(defaultTimeoutFee[0]).Add(defaultRecvFee[0]).Add(defaultTimeoutFee[0]).Add(defaultRecvFee[0])
// check if the refund acc has been refunded the recvFee
expectedRefundAccBal := refundAccBal.Add(defaultRecvFee[0]).Add(defaultRecvFee[0])
Copy link
Member

Choose a reason for hiding this comment

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

should this be adding the recv fee twice? or should it add the recv fee + ack fee?

Copy link
Member Author

Choose a reason for hiding this comment

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

It should be recv_fee twice, this is because, in this test case, only the forward relayer address is invalid, therefore only the recv_fee is refunded. The reason it is added twice is that, packetFee is paid twice in line 153

modules/apps/29-fee/keeper/migrations.go Outdated Show resolved Hide resolved
sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(0))),
},
{
"success: multiple denoms",
Copy link
Member

Choose a reason for hiding this comment

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

We could add another test or two maybe we some different mutli denom variants too

Copy link
Member

Choose a reason for hiding this comment

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

maybe an example where there's 3 different denoms and one of the fees doesn't contain it? something along those lines

Copy link
Member Author

Choose a reason for hiding this comment

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

I added another test case. Can you check?

modules/apps/29-fee/types/fee.go Show resolved Hide resolved
Copy link
Member

@AdityaSripal AdityaSripal left a comment

Choose a reason for hiding this comment

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

Approving to not block merge. As @srdtrk says, we can come to consensus on tests later and apply uniformly

@srdtrk srdtrk merged commit 6fc8159 into main Jan 17, 2024
61 of 62 checks passed
@srdtrk srdtrk deleted the serdar/issue#5509-capital-efficient-fee-2 branch January 17, 2024 09:27
mergify bot pushed a commit that referenced this pull request Jan 17, 2024
* feat: initial implementation

* test: fixed keeper tests

* test: fixed types tests

* test: all tests passing

* test: fixed fee callbacks test

* feat: implemented migration

* test: added migration tests

* docs: updated godocs

* imp: review items

* imp: review items

* imp: review items

* docs: updated godocs

* test: added multiple denoms test case for total

* specify what the migration that fails does in error message

---------

Co-authored-by: Carlos Rodriguez <carlos@interchain.io>
(cherry picked from commit 6fc8159)
srdtrk added a commit that referenced this pull request Jan 17, 2024
* feat: initial implementation

* test: fixed keeper tests

* test: fixed types tests

* test: all tests passing

* test: fixed fee callbacks test

* feat: implemented migration

* test: added migration tests

* docs: updated godocs

* imp: review items

* imp: review items

* imp: review items

* docs: updated godocs

* test: added multiple denoms test case for total

* specify what the migration that fails does in error message

---------

Co-authored-by: Carlos Rodriguez <carlos@interchain.io>
(cherry picked from commit 6fc8159)

Co-authored-by: srdtrk <59252793+srdtrk@users.noreply.github.com>
},
},
{
"success: many fees with multiple denoms in escrow",
Copy link
Contributor

@colin-axner colin-axner Jan 17, 2024

Choose a reason for hiding this comment

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

I think it'd be nice to have a test case for different incentivized packets. If I understand correctly, this does only a single iteration. If I have the following diffs (removing iteration), the tests pass:

diff --git a/modules/apps/29-fee/keeper/migrations.go b/modules/apps/29-fee/keeper/migrations.go
index 3eae34f7e..5d5701e8f 100644
--- a/modules/apps/29-fee/keeper/migrations.go
+++ b/modules/apps/29-fee/keeper/migrations.go
@@ -27,19 +27,17 @@ func (m Migrator) Migrate1to2(ctx sdk.Context) error {
        iterator := storetypes.KVStorePrefixIterator(store, []byte(types.FeesInEscrowPrefix))
        defer sdk.LogDeferred(ctx.Logger(), func() error { return iterator.Close() })
 
-       for ; iterator.Valid(); iterator.Next() {
-               feesInEscrow := m.keeper.MustUnmarshalFees(iterator.Value())
+       feesInEscrow := m.keeper.MustUnmarshalFees(iterator.Value())
 
-               for _, packetFee := range feesInEscrow.PacketFees {
-                       refundCoins := legacyTotal(packetFee.Fee).Sub(packetFee.Fee.Total()...)
+       for _, packetFee := range feesInEscrow.PacketFees {
+               refundCoins := legacyTotal(packetFee.Fee).Sub(packetFee.Fee.Total()...)
 
-                       refundAddr, err := sdk.AccAddressFromBech32(packetFee.RefundAddress)
-                       if err != nil {
-                               return err
-                       }
-
-                       m.keeper.distributeFee(ctx, refundAddr, refundAddr, refundCoins)
+               refundAddr, err := sdk.AccAddressFromBech32(packetFee.RefundAddress)
+               if err != nil {
+                       return err
                }
+
+               m.keeper.distributeFee(ctx, refundAddr, refundAddr, refundCoins)
        }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
29-fee change: state machine breaking Issues or PRs that break consensus (need to be released in at least a new minor version) priority PRs that need prompt reviews
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Capital Efficient Fee Escrow
7 participants