Aptos
Published in

Aptos

The Making of the Aptos Gas Schedule

You can’t drive a car without gas, and you won’t go far unless you know how much gas you need. Gas metering is a concept fundamental to the Aptos blockchain — it defines an abstract measurement of the amount of computational and storage resources required to execute and store a transaction. The gas schedule codifies costs across all operations on the network and calculates the amount of gas used to execute a transaction.

To produce the first production-ready gas schedule in Move in Aptos, we

Principles

There are five principles that drove our decision-making:

Measuring gas

When a user submits a transaction, they must also specify two quantities in the transaction:

The final transaction fee can be calculated by multiplying the total amount of gas consumed (measured in gas units) and the gas unit price.

For example, if a transaction consumes 670 gas units and the gas unit price specified by the user in the transaction is 100 Octa per unit, then the final transaction fee would be 670 * 100 = 67000 Octa = 0.00067 APT.

If a transaction runs out of gas during execution, the sender will be charged based on the max gas amount and all changes made by this transaction will be reverted.

Building a gas schedule

Basic configuration

There are several components of the gas schedule that do not relate to the specifics of an individual operation. These include transaction size and maximum gas units (different from the maximum gas amount that the user specifies in the transaction).

Transaction size

For most transactions, the transaction size will likely be on the order of a kilobyte. However, Move module publishing can easily be several kilobytes and the Aptos Framework is on the order of 100KB. Also, most user modules tend to be between 4KB and 40KB. Initially, we set the value of the transaction size to 32KB but the community responded quickly and asked for more space to make application development easy, so it was adjusted to 64KB.

Very large transactions induce bandwidth costs on the entire network and can have a negative impact on the performance. If abused, mempools are incentivized to ignore larger transactions, so our approach is to strike a balance between maximum transaction size and accessibility.

Maximum gas units

The maximum gas units in the gas schedule defines how many operations a transaction can perform. Note that this is different from the maximum gas amount that the user specifies in the transaction.

The gas schedule’s maximum gas units has direct implications on how long a transaction can execute. Setting it too high can result in transactions that can have negative performance implications on the blockchain. For example, a user may forget to increment the variable evaluated within a while loop resulting in an infinite loop, an unfortunately common bug. We found that even with our largest framework upgrade, we were still at less than 90% of gas schedule’s maximum gas units, which is set at 1,000,000.

Execution

In order to evaluate execution costs, we built a benchmark framework and used Valgrind to profile the Move VM while executing this framework. The output of this is a collection of annotated source code that tells us how many machine instructions each line of code has incurred.

With the help of profiling like the above, we came up with a rough estimation of the relative costs for all the Move instructions and native functions.

However, we noticed that this method had some problems with inline functions: They are not automatically included in the caller’s counts. We also saw that this only happened when we were profiling certain Move instructions, and we were able to work-around this by adding the numbers up.

Subsequently, by considering coding paradigms that enhance the robustness and the security of the system, the team arrived at a final number of the machine instructions executed. This number in turn was weighed against storage and maximum gas units to determine their current values in the gas schedule.

Storage

Whenever a ledger state item or data stored in persistent storage is accessed, the Aptos node issues a read from, or write to, the storage device. The total number of data accesses per second depends on the storage device’s bandwidth and IOPS capacities. Similar to CPU cycles for the computation part of the gas schedule, the data accesses are transient scarcities that the blockchain users compete for via a fee market while the system is under load. Furthermore, the occupied disk cost of data written is permanent on the chain. The Aptos team designed the storage gas schedule by factoring these costs.

Accessing and storing any state item imposes a cost associated with the data structure (the Jellyfish Merkle Tree) authenticating the entire blockchain state. This cost is related to the cardinality of distinct state items (out of $2^{256}$). There is also a cost proportional to the size of each item. To operate on one state item, the charge is (with exceptions described in the next section):

storage gas fee = item_fee + (byte_fee * bytes)

Read, create, and write

Any access to a state item falls into one of these three categories: read, create or write. Access is charged by the item fee and the byte fee, as shown in the above equation.

It should be noted that the storage related costs are assessed on a per-transaction basis: you only get charged once even if you read/write the same resource multiple times.

With the above considerations, we defined six storage gas parameters that form the building blocks of the total storage gas fee. See the below:

For more details, refer to https://aptos.dev/concepts/base-gas/#storage-gas.

Stable gas unit cost

Irrespective of the cost of executing an operation in market-value terms of APT or fiat currency, each operation, and the transaction itself, needs a fixed unit cost relative to the storage and execution costs. A fixed gas unit cost helps keep the gas schedule static and be decoupled from the free-market value of APT. Moreover, a proper choice of the number of precision digits for the gas unit can help keep the gas schedule static. With this in mind, the team has landed on roughly 3-digit precision to express the gas units. Hence, the cost of a transfer transaction is roughly 700 gas units.

How to adjust the gas costs

The gas schedule is stored as an on-chain configuration. Through Aptos governance proposals, the gas fees can be changed and new instructions or native functions can be seamlessly added.

The on-chain gas schedule is designed to be extensible, allowing it to be upgraded via governance proposals. As Aptos and the Aptos community continue to improve the Move VM and incorporate user feedback, the gas parameters can be adjusted over time.

Sometimes the gas formulas may require complex changes that go beyond the on-chain configuration. These gas formulas are typically coded in Rust and are distinguished by the on-chain gas feature flags. To upgrade these formulas the node software must be updated with the new formula, distinguished by a distinct gas feature flag. The node software must then be published and be substantially adopted for the node operators. Finally, a governance proposal must be published and approved to use the new gas version.

Future work

This is the first viable gas framework for Move. It required substantial modifications to both the Move VM and the Aptos-Core. We are hopeful that this work paves the way for the following future work:

Acknowledgements

Special thanks to Alnoki from Econia Labs and Robert Chen from OtterSec for their reviews and feedback.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store