|
|
@ -0,0 +1,162 @@ |
|
|
|
# RFC 011: Remove Gas From Tendermint |
|
|
|
|
|
|
|
## Changelog |
|
|
|
|
|
|
|
- 03-Feb-2022: Initial draft (@williambanfield). |
|
|
|
- 10-Feb-2022: Update in response to feedback (@williambanfield). |
|
|
|
- 11-Feb-2022: Add reflection on MaxGas during consensus (@williambanfield). |
|
|
|
|
|
|
|
## Abstract |
|
|
|
|
|
|
|
In the v0.25.0 release, Tendermint added a mechanism for tracking 'Gas' in the mempool. |
|
|
|
At a high level, Gas allows applications to specify how much it will cost the network, |
|
|
|
often in compute resources, to execute a given transaction. While such a mechanism is common |
|
|
|
in blockchain applications, it is not generalizable enough to be a maintained as a part |
|
|
|
of Tendermint. This RFC explores the possibility of removing the concept of Gas from |
|
|
|
Tendermint while still allowing applications the power to control the contents of |
|
|
|
blocks to achieve similar goals. |
|
|
|
|
|
|
|
## Background |
|
|
|
|
|
|
|
The notion of Gas was included in the original Ethereum whitepaper and exists as |
|
|
|
an important feature of the Ethereum blockchain. |
|
|
|
|
|
|
|
The [whitepaper describes Gas][eth-whitepaper-messages] as an Anti-DoS mechanism. The Ethereum Virtual Machine |
|
|
|
provides a Turing complete execution platform. Without any limitations, malicious |
|
|
|
actors could waste computation resources by directing the EVM to perform large |
|
|
|
or even infinite computations. Gas serves as a metering mechanism to prevent this. |
|
|
|
|
|
|
|
Gas appears to have been added to Tendermint multiple times, initially as part of |
|
|
|
a now defunct `/vm` package, and in its most recent iteration [as part of v0.25.0][gas-add-pr] |
|
|
|
as a mechanism to limit the transactions that will be included in the block by an additional |
|
|
|
parameter. |
|
|
|
|
|
|
|
Gas has gained adoption within the Cosmos ecosystem [as part of the Cosmos SDK][cosmos-sdk-gas]. |
|
|
|
The SDK provides facilities for tracking how much 'Gas' a transaction is expected to take |
|
|
|
and a mechanism for tracking how much gas a transaction has already taken. |
|
|
|
|
|
|
|
Non-SDK applications also make use of the concept of Gas. Anoma appears to implement |
|
|
|
[a gas system][anoma-gas] to meter the transactions it executes. |
|
|
|
|
|
|
|
While the notion of gas is present in projects that make use of Tendermint, it is |
|
|
|
not a concern of Tendermint's. Tendermint's value and goal is producing blocks |
|
|
|
via a distributed consensus algorithm. Tendermint relies on the application specific |
|
|
|
code to decide how to handle the transactions Tendermint has produced (or if the |
|
|
|
application wants to consider them at all). Gas is an application concern. |
|
|
|
|
|
|
|
Our implementation of Gas is not currently enforced by consensus. Our current validation check that |
|
|
|
occurs during block propagation does not verify that the block is under the configured `MaxGas`. |
|
|
|
Ensuring that the transactions in a proposed block do not exceed `MaxGas` would require |
|
|
|
input from the application during propagation. The `ProcessProposal` method introduced |
|
|
|
as part of ABCI++ would enable such input but would further entwine Tendermint and |
|
|
|
the application. The issue of checking `MaxGas` during block propagation is important |
|
|
|
because it demonstrates that the feature as it currently exists is not implemented |
|
|
|
as fully as it perhaps should be. |
|
|
|
|
|
|
|
Our implementation of Gas is causing issues for node operators and relayers. At |
|
|
|
the moment, transactions that overflow the configured 'MaxGas' can be silently rejected |
|
|
|
from the mempool. Overflowing MaxGas is the _only_ way that a transaction can be considered |
|
|
|
invalid that is not directly a result of failing the `CheckTx`. Operators, and the application, |
|
|
|
do not know that a transaction was removed from the mempool for this reason. A stateless check |
|
|
|
of this nature is exactly what `CheckTx` exists for and there is no reason for the mempool |
|
|
|
to keep track of this data separately. A special [MempoolError][add-mempool-error] field |
|
|
|
was added in v0.35 to communicate to clients that a transaction failed after `CheckTx`. |
|
|
|
While this should alleviate the pain for operators wishing to understand if their |
|
|
|
transaction was included in the mempool, it highlights that the abstraction of |
|
|
|
what is included in the mempool is not currently well defined. |
|
|
|
|
|
|
|
Removing Gas from Tendermint and the mempool would allow for the mempool to be a better |
|
|
|
abstraction: any transaction that arrived at `CheckTx` and passed the check will either be |
|
|
|
a candidate for a later block or evicted after a TTL is reached or to make room for |
|
|
|
other, higher priority transactions. All other transactions are completely invalid and can be discarded forever. |
|
|
|
|
|
|
|
Removing gas will not be completely straightforward. It will mean ensuring that |
|
|
|
equivalent functionality can be implemented outside of the mempool using the mempool's API. |
|
|
|
|
|
|
|
## Discussion |
|
|
|
|
|
|
|
This section catalogs the functionality that will need to exist within the Tendermint |
|
|
|
mempool to allow Gas to be removed and replaced by application-side bookkeeping. |
|
|
|
|
|
|
|
### Requirement: Provide Mempool Tx Sorting Mechanism |
|
|
|
|
|
|
|
Gas produces a market for inclusion in a block. On many networks, a [gas fee][cosmos-sdk-fees] is |
|
|
|
included in pending transactions. This fee indicates how much a user is willing to |
|
|
|
pay per unit of execution and the fees are distributed to validators. |
|
|
|
|
|
|
|
Validators wishing to extract higher gas fees are incentivized to include transactions |
|
|
|
with the highest listed gas fees into each block. This produces a natural ordering |
|
|
|
of the pending transactions. Applications wishing to implement a gas mechanism need |
|
|
|
to be able to order the transactions in the mempool. This can trivially be accomplished |
|
|
|
by sorting transactions using the `priority` field available to applications as part of |
|
|
|
v0.35's `ResponseCheckTx` message. |
|
|
|
|
|
|
|
### Requirement: Allow Application-Defined Block Resizing |
|
|
|
|
|
|
|
When creating a block proposal, Tendermint pulls a set of possible transactions out of |
|
|
|
the mempool to include in the next block. Tendermint uses MaxGas to limit the set of transactions |
|
|
|
it pulls out of the mempool fetching a set of transactions whose sum is less than MaxGas. |
|
|
|
|
|
|
|
By removing gas tracking from Tendermint's mempool, Tendermint will need to provide a way for |
|
|
|
applications to determine an acceptable set of transactions to include in the block. |
|
|
|
|
|
|
|
This is what the new ABCI++ `PrepareProposal` method is useful for. Applications |
|
|
|
that wish to limit the contents of a block by an application-defined limit may |
|
|
|
do so by removing transactions from the proposal it is passed during `PrepareProposal`. |
|
|
|
Applications wishing to reach parity with the current Gas implementation may do |
|
|
|
so by creating an application-side limit: filtering out transactions from |
|
|
|
`PrepareProposal` the cause the proposal the exceed the maximum gas. Additionally, |
|
|
|
applications can currently opt to have all transactions in the mempool delivered |
|
|
|
during `PrepareProposal` by passing `-1` for `MaxGas` and `MaxBytes` into |
|
|
|
[ReapMaxBytesMaxGas][reap-max-bytes-max-gas]. |
|
|
|
|
|
|
|
### Requirement: Handle Transaction Metadata |
|
|
|
|
|
|
|
Moving the gas mechanism into applications adds an additional piece of complexity |
|
|
|
to applications. The application must now track how much gas it expects a transaction |
|
|
|
to consume. The mempool currently handles this bookkeeping responsibility and uses the estimated |
|
|
|
gas to determine the set of transactions to include in the block. In order to task |
|
|
|
the application with keeping track of this metadata, we should make it easier for the |
|
|
|
application to do so. In general, we'll want to keep only one copy of this type |
|
|
|
of metadata in the program at a time, either in the application or in Tendermint. |
|
|
|
|
|
|
|
The following sections are possible solutions to the problem of storing transaction |
|
|
|
metadata without duplication. |
|
|
|
|
|
|
|
#### Metadata Handling: EvictTx Callback |
|
|
|
|
|
|
|
A possible approach to handling transaction metadata is by adding a new `EvictTx` |
|
|
|
ABCI method. Whenever the mempool is removing a transaction, either because it has |
|
|
|
reached its TTL or because it failed `RecheckTx`, `EvictTx` would be called with |
|
|
|
the transaction hash. This would indicate to the application that it could free any |
|
|
|
metadata it was storing about the transaction such as the computed gas fee. |
|
|
|
|
|
|
|
Eviction callbacks are pretty common in caching systems, so this would be very |
|
|
|
well-worn territory. |
|
|
|
|
|
|
|
#### Metadata Handling: Application-Specific Metadata Field(s) |
|
|
|
|
|
|
|
An alternative approach to handling transaction metadata would be would be the |
|
|
|
addition of a new application-metadata field in the `ResponseCheckTx`. This field |
|
|
|
would be a protocol buffer message whose contents were entirely opaque to Tendermint. |
|
|
|
The application would be responsible for marshalling and unmarshalling whatever data |
|
|
|
it stored in this field. During `PrepareProposal`, the application would be passed |
|
|
|
this metadata along with the transaction, allowing the application to use it to perform |
|
|
|
any necessary filtering. |
|
|
|
|
|
|
|
If either of these proposed metadata handling techniques are selected, it's likely |
|
|
|
useful to enable applications to gossip metadata along with the transaction it is |
|
|
|
gossiping. This could easily take the form of an opaque proto message that is |
|
|
|
gossiped along with the transaction. |
|
|
|
|
|
|
|
## References |
|
|
|
|
|
|
|
[eth-whitepaper-messages]: https://ethereum.org/en/whitepaper/#messages-and-transactions |
|
|
|
[gas-add-pr]: https://github.com/tendermint/tendermint/pull/2360 |
|
|
|
[cosmos-sdk-gas]: https://github.com/cosmos/cosmos-sdk/blob/c00cedb1427240a730d6eb2be6f7cb01f43869d3/docs/basics/gas-fees.md |
|
|
|
[cosmos-sdk-fees]: https://github.com/cosmos/cosmos-sdk/blob/c00cedb1427240a730d6eb2be6f7cb01f43869d3/docs/basics/tx-lifecycle.md#gas-and-fees |
|
|
|
[anoma-gas]: https://github.com/anoma/anoma/blob/6974fe1532a59db3574fc02e7f7e65d1216c1eb2/docs/src/specs/ledger.md#transaction-execution |
|
|
|
[cosmos-sdk-fee]: https://github.com/cosmos/cosmos-sdk/blob/c00cedb1427240a730d6eb2be6f7cb01f43869d3/types/tx/tx.pb.go#L780-L794 |
|
|
|
[issue-7750]: https://github.com/tendermint/tendermint/issues/7750 |
|
|
|
[reap-max-bytes-max-gas]: https://github.com/tendermint/tendermint/blob/1ac58469f32a98f1c0e2905ca1773d9eac7b7103/internal/mempool/types.go#L45 |
|
|
|
[add-mempool-error]: https://github.com/tendermint/tendermint/blob/205bfca66f6da1b2dded381efb9ad3792f9404cf/rpc/coretypes/responses.go#L239 |