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

NEP-536: Reduce the number of refund receipts #536

Merged
merged 8 commits into from
Oct 1, 2024
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions neps/nep-0536.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
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.
Copy link
Contributor

Choose a reason for hiding this comment

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

Gas refunds lead to nontrivial overhead in runtime and other places, which hurts the performance of the protocol.

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?

Copy link
Member

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.


## 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 changes the gas refund to be
```

Check failure on line 24 in neps/nep-0536.md

View workflow job for this annotation

GitHub Actions / markdown-lint

Fenced code blocks should be surrounded by blank lines [Context: "```"]

neps/nep-0536.md:24 MD031/blanks-around-fences Fenced code blocks should be surrounded by blank lines [Context: "```"]

Check failure on line 24 in neps/nep-0536.md

View workflow job for this annotation

GitHub Actions / markdown-lint

Fenced code blocks should have a language specified [Context: "```"]

neps/nep-0536.md:24 MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
refund = max(0, gas_refund - 5Tgas);
Copy link

Choose a reason for hiding this comment

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

please mention how 5T was selected.

And how will this impact the final pricing of a simple transfer and of a "simple" function call.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah 5 Tgas is curious to me. Especially since a refund is just a transfer and the cost of a transfer is only 230 Ggas.

5 Tgas seems like overcharging a lot to incentives developers to fiddle with their gas numbers. If this means it's considered essential for contract developers to do exact gas estimates from now on, that's a massive decline in Devx if you ask me and I am not sure if this is really worth it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Note, that the gas refunds also touch the access key from which they were issued to refund the gas. And the transfer is about 460 (since it's send + exec)

The penalty should be large enough to also give developers estimation range. For example, if a developer estimates their call to be from 7 to 9Tgas. They can attach 10Tgas and no refunds will be generated. This will decrease the load on the shard by removing extra refunds.

```

Check failure on line 26 in neps/nep-0536.md

View workflow job for this annotation

GitHub Actions / markdown-lint

Fenced code blocks should be surrounded by blank lines [Context: "```"]

neps/nep-0536.md:26 MD031/blanks-around-fences Fenced code blocks should be surrounded by blank lines [Context: "```"]
per receipt. In other words, for each gas refund, there is a 5Tgas penalty that is applied. The penalty is added to gas burnt. This means that for receipts that involve gas refund less than 5Tgas, there will be no gas refunds.
Copy link
Contributor

Choose a reason for hiding this comment

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

I suggest to not include the full penalty into the gas_burnt since it would decrease the throughput of the network by artificially taking extra 5Tgas from every function call receipt.

Instead we include this cost into tx_burnt_amount. The gas_burnt should include only send+exec fee for action_receipt+transfer which is the cost of the actual refund receipt. But we burn exec fee immediately, because the refund receipts don't have the burnt gas.

In this case we account for gas refunds at the time of generation, but discourage them from happening by burning the fee.
In the future NEP, the 5Tgas penalty should be changed to be a dynamic fee that grows with the block height until it reaches 300Tgas in which case no new gas refunds are generated.


## 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`. There is no gas refund for actions other than function calls.

Check failure on line 32 in neps/nep-0536.md

View workflow job for this annotation

GitHub Actions / markdown-lint

Lists should be surrounded by blank lines [Context: "* When a transaction is conver..."]

neps/nep-0536.md:32 MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "* When a transaction is conver..."]
bowenwang1996 marked this conversation as resolved.
Show resolved Hide resolved
* For function calls, if X gas is attached during the execution of a receipt and Y gas is burnt, then max(0, X-Y-5Tgas) is refunded at the original gas price.

## 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.
Copy link
Member

Choose a reason for hiding this comment

The 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 malicious user sends multiple transactions at a low gas price enough to fill a block. Each transaction calls the same contract in a loop until it runs out of gas, spanning a significant period of time.

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.

Copy link
Contributor

Choose a reason for hiding this comment

The 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.


Copy link
Contributor

Choose a reason for hiding this comment

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

Let's consider the following scenario:

  • tx with 300TG is included block b1, and converted into receipts (containing function calls).
  • Eventually, only 50TG was used to process all receipts.

How does this impact the block limit?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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

This proposal changes how gas refund works today and as a result, users may need to pay slightly more when they send a function call transaction. However, the difference is quite small (0.0005N at most).


## 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/).
Loading