-
Notifications
You must be signed in to change notification settings - Fork 137
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
NEP-536: Reduce the number of refund receipts #536
Changes from 5 commits
9fbdaaf
bdedc83
8b39ab5
55f192f
758104e
c844ae6
6acad90
b418116
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
--- | ||
NEP: 536 | ||
Title: Reduce the number of gas refunds | ||
Authors: Evgeny Kuzyakov <[email protected]>, Bowen Wang <[email protected]> | ||
Status: New | ||
DiscussionsTo: https://github.com/near/NEPs/pull/536 | ||
Type: Protocol | ||
Version: 1.0.0 | ||
Created: 2024-03-12 | ||
LastUpdated: 2023-03-12 | ||
--- | ||
|
||
## Summary | ||
|
||
[Gas refund](https://docs.near.org/concepts/basics/transactions/gas#attach-extra-gas-get-refunded) is a mechanism that allows users to get refunded for gas that is not used during the execution of a smart contract. Due to [pessimistic gas pricing](https://docs.near.org/concepts/basics/transactions/gas-advanced#pessimistic-gas-price-inflation), however, even transactions that do not involve function calls generate refunds because users need to pay at a high price and get refunded the difference. Gas refunds lead to nontrivial overhead in runtime and other places, which hurts the performance of the protocol. This proposal aims to reduce the number of gas refunds and prepare for future changes that completely remove gas refunds. | ||
|
||
## Motivation | ||
|
||
Refund receipts create nontrivial overhead: they need to be merklized and sent across shards. In addition, the processing of refund receipts requires additional storage reads and writes, which is not optimal for the performance of the protocol. In addition, when there is congestion, refund receipts may be delayed during execution. Whenever this happens, it requires two additional storage writes to store a gas refund receipt and two additional reads and writes when they are later processed, which incurs a significant overhead. To optimize the performance of the protocol under congestion, it is imperative that we reduce the number of refund receipts. | ||
|
||
## Specification | ||
|
||
Pessimistic gas pricing is removed as a part of this change. This means that transactions that do not involve function calls will not generate gas refund receipts as a result. For function calls, this proposal introduces cost of refund to be | ||
``` | ||
Check failure on line 24 in neps/nep-0536.md GitHub Actions / markdown-lintFenced code blocks should be surrounded by blank lines [Context: "```"]
|
||
REFUND_FIXED_COST = action_receipt_creation + action_transfer + action_add_function_call_key | ||
refund_cost = max(REFUND_FIXED_COST, 0.05 * gas_refund); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be nice to justify this 5% number. How is it chosen instead of 6% or 4%? What network data is used to make this decision? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is an arbitrary number. The goal here is to start penalizing users for attaching too much gas. The percentage should be large enough so that someone attaching 100Tgas or more is penalized for doing so but also small enough so that a callback with a fixed amount of gas reserved are not heavily impacted because the contract is potentially already locked. I think a smaller percentage would work well too. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Shouldn't fixed gas callbacks be unaffected by this change? This change effectively makes refunds smaller, but there is no refund for gas reserved for promises until after those receipts have already executed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The callbacks themselves are unaffected, but the amount of gas refund would be |
||
``` | ||
Check failure on line 27 in neps/nep-0536.md GitHub Actions / markdown-lintFenced code blocks should be surrounded by blank lines [Context: "```"]
|
||
per receipt. The refund fixed cost includes consideration for implicit accounts (created on transfer) and refund for access key allowance, which requires an access key update. The design of refund cost is supposed to penalize developers from attaching too much gas | ||
and creating unnecessary refunds. Some examples: | ||
* If the contract wants to refund 280Tgas, burning 5% of it would be about 14Tgas, which is a significant cost and developers would be encouraged to optimize it on the frontend. | ||
Check failure on line 30 in neps/nep-0536.md GitHub Actions / markdown-lintLists should be surrounded by blank lines [Context: "* If the contract wants to ref..."]
|
||
* If refund is 100Tgas, then 5% is 5Tgas, which is still significant and discourages developers from doing so. | ||
* If the refund is <10Tgas (very common case for cross-contract call self-callbacks), the penalty should be just 500Ggas, which is less than the gas refund cost. So only the fixed refund cost will be charged from gas to spawn the gas refund receipt. No UX will be broken for legacy cross-contract call contracts, so long as frontend correctly estimates the required gas in worst case scenario. | ||
|
||
|
||
## Reference Implementation | ||
|
||
The protocol changes are as follows: | ||
* When a transaction is converted to a receipt, there is no longer a `pessmistic_gas_price` multiplier when the signer balance is deducted. Instead, the signer is charged `transaction_gas_cost * gas_price`. If the transaction succeeds, then unless the transaction contains a function call action, it will not generate any refund. On the other hand, when a transaction with multiple action fails, there is gas refund for the rest of unexecuted actions, same as how the protocol works today. | ||
Check failure on line 38 in neps/nep-0536.md GitHub Actions / markdown-lintLists should be surrounded by blank lines [Context: "* When a transaction is conver..."]
|
||
* For function calls, if X gas is attached during the execution of a receipt and Y gas is used+burnt, then `max(0, X-Y-refund_cost)` is refunded at the original gas price where `refund_cost = max(REFUND_FIXED_COST, 0.05 * X-Y)`. In the case the refund is 0 then no refund receipt is generated. | ||
* Tokens burnt on refund cost is counted towards tx_balance_burnt and the part over `REFUND_FIXED_COST` is not counted towards gas limit to avoid artificially limiting throughput. | ||
* Because refund cost is now separate, action costs do not need to account for refund and therefore should be recalculated and reduced. | ||
|
||
## Security Implications | ||
|
||
This change may lead to less correct charging for transactions when there is congestion. However, the entire gas price mechanism needs to be rethought any ways and when only one or two shards are congested, the gas price wouldn't change so there is no difference. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This brings back the known attack of a malicious user clogging the network for a low gas price. The attack: The cost of the attack with this change will be smaller since the gas is paid at the cost of the gas in the beginning. This attack can be done repeatedly by waiting until the gas price decreases, keeping the network from the POV of genuine users as either congested or with high gas prices. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Valid concern which should be addressed with receipt execution order based either on gas price or priority fee, but it's a separate NEP. Even right now the attack above is not mitigated with the pessimistic gas because you can spawn multiple transactions in a short period of time with low attached gas. It only makes it marginally more expensive which is not worth sacrificing for better UX. |
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's consider the following scenario:
How does this impact the block limit? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It doesn't affect how gas used is computed, so there is no impact on block limit |
||
## Alternatives | ||
|
||
One altnerative is to completely remove gas refunds by burning all prepaid gas. This idea was [discussed](https://github.com/near/NEPs/issues/107) before. However, it would be a very drastic change and may very negatively damage the developer experience. | ||
The approach outlined in this proposal has less impact on developer and user experience and may be extended to burning all prepaid gas in the future. | ||
|
||
## Future possibilities | ||
|
||
* Burning all prepaid gas is a natural extension to this proposal, which would completely get rid of gas refunds. This, however, would be a major change to the developer experience of NEAR and should be treated cautiously. | ||
At the very least, developers should be able to easily estimate how much gas a function within a smart contract is going to consume during execution. | ||
|
||
## Consequences | ||
|
||
[This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones. Record any concerns raised throughout the NEP discussion.] | ||
|
||
### Positive | ||
|
||
* p1 | ||
|
||
### Neutral | ||
|
||
* n1 | ||
|
||
### Negative | ||
|
||
* n1 | ||
|
||
### Backwards Compatibility | ||
|
||
Developers may need to change the amount of gas they attach when they write client side code that interacts with smart contracts to avoid getting penalized. However, this is not too difficult to do. | ||
|
||
## Changelog | ||
|
||
[The changelog section provides historical context for how the NEP developed over time. Initial NEP submission should start with version 1.0.0, and all subsequent NEP extensions must follow [Semantic Versioning](https://semver.org/). Every version should have the benefits and concerns raised during the review. The author does not need to fill out this section for the initial draft. Instead, the assigned reviewers (Subject Matter Experts) should create the first version during the first technical review. After the final public call, the author should then finalize the last version of the decision context.] | ||
|
||
### 1.0.0 - Initial Version | ||
|
||
> Placeholder for the context about when and who approved this NEP version. | ||
|
||
#### Benefits | ||
|
||
> List of benefits filled by the Subject Matter Experts while reviewing this version: | ||
|
||
* Benefit 1 | ||
* Benefit 2 | ||
|
||
#### Concerns | ||
|
||
> Template for Subject Matter Experts review for this version: | ||
> Status: New | Ongoing | Resolved | ||
|
||
| # | Concern | Resolution | Status | | ||
| --: | :------ | :--------- | -----: | | ||
| 1 | | | | | ||
| 2 | | | | | ||
|
||
## Copyright | ||
|
||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.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.
I'm curious how much this really is, do we have numbers on it? I would expect there is about 1 refund (0.23 Tgas) for 1 function call (at least 4.8 Tgas). So I would think it's less than 5% of total workload in terms of gas.
Also, the size of a transfer is tiny and shouldn't be a problem for state witness sizes.
Am I missing something?
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.
I am also curious about which percent of the gas refunds are above 5T vs which percent are below.
It would be nice to have a graph where we see the percentage of transactions in some period of time (say last month) of the refund amount vs the percent of transactions below this amount. This could show the impact of the NEP on users and network performance.