|
1 | 1 | [#1599]: https://github.com/CosmWasm/cosmwasm/pull/1599 |
2 | 2 | [JSON numbers]: https://www.json.org/ |
3 | 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 |
| 4 | +[inspired by NEAR]: https://docs.near.org/concepts/protocol/gas |
5 | 5 | [#1120]: https://github.com/CosmWasm/cosmwasm/pull/1120 |
6 | 6 |
|
7 | 7 | # Gas |
8 | 8 |
|
9 | 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 |
| 10 | +storage cost. Gas unit is 1, i.e. you can think of it as countable points. Gas consumption is |
| 11 | +deterministic, so executing the same code costs the same amount of gas across all hardware and |
12 | 12 | operating systems. |
13 | 13 |
|
14 | | -## CosmWasm gas vs. Cosmos SDK gas |
| 14 | +## CosmWasm gas versus Cosmos SDK gas |
15 | 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. |
| 16 | +CosmWasm charges gas for: |
| 17 | +- Wasm operations, |
| 18 | +- calls to host functions, |
| 19 | +- calls to the Cosmos SDK. |
| 20 | + |
| 21 | +_**CosmWasm gas**_ is different from _**Cosmos SDK gas**_ as the numbers in CosmWasm are much larger. |
18 | 22 | Since we charge gas for arbitrary user defined operations, we need to charge each Wasm operation |
19 | 23 | individually and cannot group larger tasks together. As a result, the gas values become much larger |
20 | 24 | 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. |
| 25 | +to translate between _**Cosmos SDK gas**_ and _**CosmWasm gas**_. |
| 26 | +It was measured and set to `140 000` a while ago and can be adjusted when necessary. |
23 | 27 |
|
24 | 28 | ## CosmWasm gas pricing |
25 | 29 |
|
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. |
| 30 | +For CosmWasm gas, the target gas consumption is **1 Teragas per second** (Tera = $10^{12}$). |
| 31 | +This idea is [inspired by NEAR]; see their excellent documentation for more details. Summarizing: |
| 32 | + |
| 33 | +$$ 1\ Teragas = (shortly)\ 1\ Tgas = 10^{12}\ gas $$ |
28 | 34 |
|
29 | 35 | In order to meet this target, we execute Argon2 in a test contract ([#1120]). This is a CPU and |
30 | 36 | 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. |
| 37 | +(before CosmWasm 1.0), this consumed **96837752** gas and took 15 ms on our CI system. |
| 38 | +The ideal cost per Wasm operation for this system is: |
| 39 | + |
| 40 | +$$ {10^{12} : {96837752 \over {15 \times 10^{-3}}}} = 154 $$ |
| 41 | + |
| 42 | +This is rounded to $\lfloor 154 \rfloor = \mathbf{150}$ for simplicity. |
| 43 | + |
| 44 | +**CosmWasm 2.1 update** |
34 | 45 |
|
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. |
| 46 | +All gas values were re-evaluated and adjusted to meet the **1 Teragas per second** target mentioned above. |
| 47 | +A rerun of the Argon2 test contract consumed **5270718300** gas with the |
| 48 | +previous cost of 150, so the operation count was: |
| 49 | + |
| 50 | +$$ {5270718300 \over 150} = 35138122 $$ |
| 51 | + |
| 52 | +This took 6 ms on our benchmark server, so the new cost per operation is: |
| 53 | + |
| 54 | +$$ {10^{12} : {35138122 \over {6 \times 10^{-3}}}} = 171 $$ |
40 | 55 |
|
41 | | -Benchmarking system: |
| 56 | +This is rounded to $\lfloor 171 \rfloor = \mathbf{170}$ for simplicity. |
| 57 | + |
| 58 | +**Benchmarking system** |
42 | 59 |
|
43 | 60 | - CPU: Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz (4 cores, 8 threads) |
44 | 61 | - RAM: 32GB DDR4 2133 MHz |
45 | 62 |
|
46 | | -Each machine is different, we know that. But the above target helps us in multiple ways: |
| 63 | +Each machine is different, this is obvious. But the above model helps us in multiple ways: |
47 | 64 |
|
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. |
| 65 | +- develop an intuition what it means to burn N units of gas or how much gas can be used if a block |
| 66 | + should be executable in 1 second, |
| 67 | +- have a target for adjustments when the Wasm runtime becomes faster or slower, |
| 68 | +- allow pricing of calls that are not executed in Wasm, such as crypto APIs or Cosmos APIs, |
| 69 | +- find significant over- or underpricing. |
53 | 70 |
|
54 | 71 | ## Gas overflow potential |
55 | 72 |
|
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**. |
| 73 | +CosmWasm gas aims for **1 Teragas per second**, which means that the 64-bit unsigned integer range exceeds |
| 74 | +after 18 million seconds: |
| 75 | + |
| 76 | +$$ \frac{2^{64} - 1}{10^{12}} \approx 18446744\ seconds \approx 5124\ hours \approx 213\ days $$ |
| 77 | + |
| 78 | +Assuming a maximal supported block execution time of 30 seconds, the gas price has to be overpriced |
| 79 | +by a factor of **614891** in order to exceed the 64-bit unsigned integer range: |
61 | 80 |
|
62 | | -Cosmos SDK gas uses values that are smaller by a factor of 150, so those don't overflow as well. |
| 81 | +$$ \frac{2^{64} - 1}{30 \times 10^{12}} \approx 614891\ {Teragas \over s} $$ |
| 82 | + |
| 83 | + |
| 84 | +Since serious over- or underpricing is considered a bug, using 64-bit unsigned integer |
| 85 | +for gas measurements is **considered safe**. |
| 86 | + |
| 87 | +Cosmos SDK gas uses values that are smaller by a factor of 170, so those don't overflow as well. |
63 | 88 | Since no Cosmos SDK gas values are processed inside of this repository, this is not our main |
64 | 89 | concern. However, it's good to know that we can safely pass them in 64-bit fields, as long as the |
65 | 90 | full range is supported. This is the case for the C API as well as [JSON numbers] as long as both |
66 | 91 | 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 |
| 92 | +implementations don't support integers, and convert them to IEEE–754 doubles, which has a safe |
68 | 93 | integer range up to about 53 bit (e.g. JavaScript and jq). |
69 | 94 |
|
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 |
| 95 | +## Gas changes in CosmWasm |
75 | 96 |
|
76 | 97 | In all versions before 2.0, the gas values were bigger by a factor of **1000**. |
77 | 98 | There is no need to have them this big and in order to reduce the risk of |
78 | 99 | overflow, the gas values were lowered in this issue [#1599]. |
79 | 100 |
|
80 | 101 | Below is a breakdown of what this change entails: |
81 | 102 |
|
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 | |
| 103 | +| | CosmWasm 1.x | CosmWasm 2.0 | CosmWasm 2.1 | |
| 104 | +|-----------------------------------------------------|:------------:|:------------:|:------------:| |
| 105 | +| **Cost target** | 1 Tgas/ms | 1 Tgas/s | 1 Tgas/s | |
| 106 | +| **Exceeds 64-bit unsigned<br/>integer range after** | 5 hours | 5124 hours | 5124 hours | |
| 107 | +| **Cost per Wasm operation** | 150.000 | 150 | 170 | |
| 108 | +| **Multiplier** | 140.000.000 | 140.000 | 140.000 | |
0 commit comments