-
Notifications
You must be signed in to change notification settings - Fork 46
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
WIP: Feature/transaction fees #323
Conversation
The idea for dynamic fees is we define a bunch of business logic that will be executed in the fee decorator, that will match messages by their type and use whatever unique properties (or not unique) to construct an id out of Path() + this info for lookups, with fallback to the original Path(). I think this will be a sort of a callback passed directly from the implementing app to avoid dependencies on other packages in fee package. |
Codecov Report
@@ Coverage Diff @@
## master #323 +/- ##
========================================
+ Coverage 69.5% 69.6% +<.1%
========================================
Files 134 134
Lines 6183 6219 +36
========================================
+ Hits 4302 4330 +28
- Misses 1468 1472 +4
- Partials 413 417 +4
Continue to review full report at Codecov.
|
72b75b0
to
87611b0
Compare
@ethanfrey @alpe After taking another look at this I've moved my initial fee logic to cash, cause it seems like we'll need the FeeTx and the logic to figure out who pays to whom. This raises a couple of concerns, one of which being the following: we want this to support batch and be downstream from it, but we have cash.FeeDectorator upstream from hashlock, which is a conflict then. Looking into it further, but would appreciate some input on the approach. |
@ruseinov can you explain a bit more how your implementation will work? I can see only state management code and no actual fee collection. My understanding of this functionality is that we have the possibility to declare fees for each transaction type. Somewhere we keep a mapping of Does it make sense to keep this functionality as a separate extension and not part of the |
After reflection I agree. This is not a singleton config, but a bucket with a different entry for each tx type with fees registered |
I would ignore all thinking for what you call "dynamic fees" or fees that depend on the content, not just the type of the message. For static fees, I agree with this. |
Note from the issue:
All fees go to the same location. This basically sets a higher filter for transactions that contain messages with product fees |
Huh? This only is a problem as you want to re-use the cash.FeeDecorator (the anti-spam measure) for a product fee filter.... why not another decorator. Since you hit some design limits, I would appreciate you documenting the current plan better before proceeding with the code, so I can give a higher level feedback. I can give good pointer then, we talking about where is calculated and where does it flow... |
btw, good that you started this to give time for comments on the design, but please finish up the errors refactor before investing much more time coding this, and giving a bit of time for design feedback |
@ethanfrey I started this exactly because it is never 100% clear on how to do anything before you approach it + I was stuck on my first error pr review. So this is now a good placeholder for discussions, while I can focus on errors, when I'm blocked - I circle back here. |
@husio there is no code for transactions yet, because we needed to have a discussion first, hence this PR with a bunch of questions and the only implementation detail I know for sure won't change. |
@ethanfrey So in my understanding the hashlock is going to be a problem for any kind of fees, not just anti-spam. The idea is:
|
When using a hash lock, the transaction still has a signature (that pays the fees) and a hash preimage (to authorize the release). The hash lock never pays fees. In fact it can go anywhere above batch Or even after batch, just duplicate work |
@ethanfrey right, I thought we could move it too. in this case I would argue that having a combined decorator makes more sense, as the base code is mostly the same, or at least I expect it to be. |
I mostly agree with the above comment, but have some additions to keep them separate, cuz really, most chains have no product fee, while almost all have anti spam |
Well, that’s easily pluggable, we can simply turn off that feature if it’s not configured in genesis. If that does not make sense - I can try a base handler approach to share some of this code or similar. |
In short, add a field to CheckResult and Deliver Result (they are weave internal) for minimum allowed fee. On the way in the fee filter checks against anti spam fee. On the way out it checks against return value (if the handlers set this) Each handler can add the antispam fee. Or we can make a simple decorator beyond batch that does the lookup and adds to the result, and then add it in batch just like gas price. Somehow I prefer to keep the required fee logic generic in the fee Middleware and focus on the transfer and enforcing. And then calculate needed fees elsewhere in an app dependent manner, where it is easy to extend for dynamic fees |
I’m not sure I got it right. So do you want to keep anti-spam as is and deal with product fee elsewhere? I think the approach with putting this beyond batch makes more sense then, as it’s easier to understand and implement. Let’s do this. |
Exactly. |
I was trying to work out the above comment a bit more (wrote on the phone while waiting for my son). I still agree with most of it, but could flesh it out.
I think this leaves a clean separation of concerns, and if someone wants to add new fee requirements, this would be orthogonal. Such as a module that adds a subjective CheckTx requirement that can be adjusted by each validator (this is what they did in Game of Stakes). It would just set this RequiredFee field. Sounds good? I see just one problem here, which is that the FeeMiddleware is outside the Checkpoint. Which means if a tx gets in the block with a fee that is bigger than the anti-spam fee, but not as big as the product fee, it will fail, but still lose the fee. Actually, this is a problem in any case, we deduct the entire fee in any case. Maybe we don't have to worry about this. Maybe there is a clever idea to fix it? Anyway, this is more or less my design. Happy for improvements. |
The approach sounds good, I need to think a bit more about it to see what option I'd prefer, I also think this will require some light prototyping to see what looks most eloquent. Let me think about the checkpoint issue a bit more too. |
I mean, it is also good to define expectations here... With the current setup (anti-spam), insufficient fees cause rejection in CheckTx and never make it to a block. If it does make it into a block, all fees are deducted (assuming the fee account owner has signed) before executing any transactions, and are not rolled back on failure. The entire amount of fees are deducted in any case. Before working out product fee behavior, maybe we should consider if the above is optimal. Another approach:
Maybe there is another approach (not technical, but business logic-level) of how we deduct fees. @alpe maybe you have some thoughts here about fee deduction |
I like the idea of adding a In normal business I would say let's take all the fees on error as well, prepare a budget and let customer support handle the edge cases until some new learnings can be applied to the code. |
Yeah, I like the idea of deducting just the anti-spam fee too I guess |
Simple adjustment to the fee handler: On the way in:
On the way out:
However, if my transaction empties my account and I cannot cover my fee at the end, the transaction logic was still committed and not rolled back. Maybe we can adjust this... More complex adjustment to the fee handler: On the way in:
On the way out:
A bit trickier, but more correct I think |
Good discussion, after this we agreed on a new approach, documented in #232 under "update". Closing this one in favor of other PRs that take a different approach with fees |
Fixes #232
I have reiterated on this a couple of times and it seems like the best solution is to init from genesis and not gconf, as we need to support lookups.
Also, the current idea for dynamic fees is as follows:
for static fees we just use
nft/approval/grant
for dynamic fees we go
nft/approval/grant:unique_name
There is no reason to complicate this further as this logic could be easily defined in our controllers and that well save us the space and the indices, allow for easy fallbacks and is pretty flexible.
I'd like to hear some thoughts about that though before continuing.