|
| 1 | +[#1599]: https://github.com/CosmWasm/cosmwasm/pull/1599 |
| 2 | +[JSON numbers]: https://www.json.org/ |
| 3 | +[default-gas-multiplier]: https://github.com/CosmWasm/wasmd/blob/04cb6e5408cc54c27247b0b327dfa99769d5103c/x/wasm/types/gas_register.go#L34 |
| 4 | +[near-gas]: https://docs.near.org/concepts/protocol/gas |
| 5 | +[#1120]: https://github.com/CosmWasm/cosmwasm/pull/1120 |
| 6 | + |
| 7 | +# Gas |
| 8 | + |
| 9 | +Gas is a way to measure computational expense of a smart contract execution, including CPU time and |
| 10 | +storage cost. Its unit is 1, i.e. you can think of it as countable points. Gas consumption is |
| 11 | +deterministic, so executing the same thing costs the same amount of gas across all hardware and |
| 12 | +operating systems. |
| 13 | + |
| 14 | +## CosmWasm gas vs. Cosmos SDK gas |
| 15 | + |
| 16 | +CosmWasm charges gas for Wasm operations, calls to host functions and calls to the Cosmos SDK. |
| 17 | +_**CosmWasm gas**_ is different from _**Cosmos SDK gas**_ as the numbers here are much larger. |
| 18 | +Since we charge gas for arbitrary user defined operations, we need to charge each Wasm operation |
| 19 | +individually and cannot group larger tasks together. As a result, the gas values become much larger |
| 20 | +than in Cosmos SDK even for very fast executions. There is a [multiplier][default-gas-multiplier] |
| 21 | +to translate between _**CosmWasm gas**_ and _**Cosmos SDK**_ gas. |
| 22 | +It was measured and set to 100 a while ago and can be adjusted when necessary. |
| 23 | + |
| 24 | +## CosmWasm gas pricing |
| 25 | + |
| 26 | +For CosmWasm gas, the target gas consumption is 1 Teragas ($10^{12}$ gas) per second. This idea is |
| 27 | +[inspired by NEAR][near-gas] and we encourage you to read their excellent docs on that topic. |
| 28 | + |
| 29 | +In order to meet this target, we execute Argon2 in a test contract ([#1120]). This is a CPU and |
| 30 | +memory intense job that does not call out into the host. At a constant gas cost per operation of 1 |
| 31 | +(pre CosmWasm 1.0), this consumed 96837752 gas and took 15ms on our CI system. The ideal cost per |
| 32 | +operation for this system is `10^12 / (96837752 / (15 / 1000))`: 154. This is rounded to 150 for |
| 33 | +simplicity. |
| 34 | + |
| 35 | +CosmWasm 2.1 update: All gas values were re-evaluated and adjusted to meet the 1 Teragas/second |
| 36 | +target mentioned above. A rerun of the Argon2 test contract consumed 5270718300 gas with the |
| 37 | +previous cost of 150, so the operation count was `5270718300 / 150 = 35138122`. This took 6ms on our |
| 38 | +benchmark server, so the new cost per operation is `10^12 / (35138122 / (6 / 1000))`: 171. This is |
| 39 | +rounded to 170 for simplicity. |
| 40 | + |
| 41 | +Benchmarking system: |
| 42 | + |
| 43 | +- CPU: Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz (4 cores, 8 threads) |
| 44 | +- RAM: 32GB DDR4 2133 MHz |
| 45 | + |
| 46 | +Each machine is different, we know that. But the above target helps us in multiple ways: |
| 47 | + |
| 48 | +1. Develop an intuition what it means to burn X gas or how much gas can be used if a block should be |
| 49 | + executable in e.g. 1 second. |
| 50 | +2. Have a target for adjustments, e.g. when the Wasm runtime becomes faster or slower. |
| 51 | +3. Allow pricing of calls that are not executed in Wasm, such as crypto APIs. |
| 52 | +4. Find significant over- or underpricing. |
| 53 | + |
| 54 | +## Gas overflow potential |
| 55 | + |
| 56 | +CosmWasm gas aims for Teragas/second, i.e. the 64-bit unsigned integer range exceeds |
| 57 | +after 18 million seconds (≈5000 hours)<sup>1)</sup>. Assuming a maximal supported block execution |
| 58 | +time of 30 seconds, the gas price has to be over-priced by a factor of 614891 (614891 Teragas/second) |
| 59 | +in order to exceed the 64-bit unsigned integer range<sup>2)</sup>. Since serious over- or underpricing |
| 60 | +is considered a bug, using 64-bit unsigned integer for gas measurements is **considered safe**. |
| 61 | + |
| 62 | +Cosmos SDK gas uses values that are smaller by a factor of 150, so those don't overflow as well. |
| 63 | +Since no Cosmos SDK gas values are processed inside of this repository, this is not our main |
| 64 | +concern. However, it's good to know that we can safely pass them in 64-bit fields, as long as the |
| 65 | +full range is supported. This is the case for the C API as well as [JSON numbers] as long as both |
| 66 | +sides support integers in their JSON implementation. Go and Rust do that while many other |
| 67 | +implementations don't support integers, and convert them to IEEE-754 doubles, which has a safe |
| 68 | +integer range up to about 53 bit (e.g. JavaScript and jq). |
| 69 | + |
| 70 | +<sup>1)</sup> $\frac{2^{64} - 1}{10^{12}} \approx 18446744s$, ${18446744 \over 3600} \approx 5124 h$ |
| 71 | + |
| 72 | +<sup>2)</sup> $\frac{2^{64} - 1}{30 \times 10^{12}} \approx 614891$ |
| 73 | + |
| 74 | +## Changes from version 1.x to 2.0 of CosmWasm |
| 75 | + |
| 76 | +In all versions before 2.0, the gas values were bigger by a factor of **1000**. |
| 77 | +There is no need to have them this big and in order to reduce the risk of |
| 78 | +overflow, the gas values were lowered in this issue [#1599]. |
| 79 | + |
| 80 | +Below is a breakdown of what this change entails: |
| 81 | + |
| 82 | +| | CosmWasm 1.x | CosmWasm 2.x | |
| 83 | +|-----------------------------------------------------|:---------------------:|:-------------------------:| |
| 84 | +| **Cost target** | 1 Teragas/millisecond | 1 Teragas/second | |
| 85 | +| **Exceeds 64-bit unsigned<br/>integer range after** | 5 hours | 5124 hours<br/>≈ 213 days | |
| 86 | +| **Cost per Wasm operation** | 150.000 | 150 | |
| 87 | +| **Multiplier** | 140.000.000 | 140.000 | |
0 commit comments