Gno Fee Taskforce WIP
Goal
- Find how much gas is used for common types of transactions
- Estimate the amount of transactions of each type can be done by an average GNOT token holder
- Recommend gas fee adjustments
Total number of accounts: 656,740
Totals
- All: 752,454,999,663,089 ugnot
- Top 1000 accounts: 621,654,079,086,191 ugnot
- Bottom 1000 accounts: 2,000 ugnot
- All excluding the top and bottom 1000: 130,800,920,574,898 ugnot
Weight
- Top 1000 accounts (0.15% of the total number of accounts) hold 82.62% of the total balance
- Bottom 1000 accounts (0.15% of the total number of accounts) hold 0.0000000003% of the total balance
Averages
- All: 1,145,742,606.91 ugnot
- Top 1000 accounts: 621,654,079,086.19 ugnot
- Bottom 1000 accounts: 2.00 ugnot
- All excluding the top and bottom 1000: 199,775,362.09 ugnot
Spread
- Variance of balances: 18,446,744,073,709,551,615
- Standard deviation of balances: 4,294,967,296
Percentiles
- 99th percentile of balances: 4,060,691,105 ugnot
- 95th percentile of balances: 552,862,608 ugnot
- 90th percentile of balances: 239,673,979 ugnot
- 75th percentile of balances: 52,359,891 ugnot
- 50th percentile of balances: 8,388,001 ugnot (median)
- 25th percentile of balances: 194,150 ugnot
- 10th percentile of balances: 7,496 ugnot
- 5th percentile of balances: 4,872 ugnot
- 1st percentile of balances: 9 ugnot
Gas usage
- Global average cost: 6,744,429 ugnot
- Median user (50th percentile) can call 1.24 times
- Bottom quarter user (25th percentile) can call 0.03 times
- Average user can call 169.88 times
- Average (excluding top and bottom 1000) can call 29.62 times
Bank transfer
- Average cost: 45,116 ugnot
- Median user (50th percentile) can transfer 185.92 times
- Bottom quarter user (25th percentile) can transfer 4.30 times
- Average user can transfer 25,395.48 times
- Average (excluding top and bottom 1000) can transfer 4,428.04 times
Realm "gno.land/r/demo/boards"
- Realm average cost: 6,357,615 ugnot
- Median user (50th percentile) can call 1.32 times
- Bottom quarter user (25th percentile) can call 0.03 times
- Average user can call 180.22 times
- Average (excluding top and bottom 1000) can call 31.42 times
Func "CreateBoard"
- Func "CreateBoard" average cost: 10,282,870 ugnot
- Median user (50th percentile) can call 0.82 times
- Bottom quarter user (25th percentile) can call 0.02 times
- Average user can call 111.42 times
- Average (excluding top and bottom 1000) can call 19.43 times
Func "GetBoardIDFromName"
- Func "GetBoardIDFromName" average cost: 1,137,910 ugnot
- Median user (50th percentile) can call 7.37 times
- Bottom quarter user (25th percentile) can call 0.17 times
- Average user can call 1,006.88 times
- Average (excluding top and bottom 1000) can call 175.56 times
Func "CreateThread"
- Func "CreateThread" average cost: 6,821,067 ugnot
- Median user (50th percentile) can call 1.23 times
- Bottom quarter user (25th percentile) can call 0.03 times
- Average user can call 167.97 times
- Average (excluding top and bottom 1000) can call 29.29 times
Func "CreateReply"
- Func "CreateReply" average cost: 6,983,445 ugnot
- Median user (50th percentile) can call 1.20 times
- Bottom quarter user (25th percentile) can call 0.03 times
- Average user can call 164.07 times
- Average (excluding top and bottom 1000) can call 28.61 times
Func "DeletePost"
- Func "DeletePost" average cost: 6,562,785 ugnot
- Median user (50th percentile) can call 1.28 times
- Bottom quarter user (25th percentile) can call 0.03 times
- Average user can call 174.58 times
- Average (excluding top and bottom 1000) can call 30.44 times
Realm "gno.land/r/demo/grc20factory"
- Realm average cost: 7,131,244 ugnot
- Median user (50th percentile) can call 1.18 times
- Bottom quarter user (25th percentile) can call 0.03 times
- Average user can call 160.67 times
- Average (excluding top and bottom 1000) can call 28.01 times
Func "NewWithAdmin"
- Func "NewWithAdmin" average cost: 7,538,156 ugnot
- Median user (50th percentile) can call 1.11 times
- Bottom quarter user (25th percentile) can call 0.03 times
- Average user can call 151.99 times
- Average (excluding top and bottom 1000) can call 26.50 times
Func "Mint"
- Func "Mint" average cost: 6,575,337 ugnot
- Median user (50th percentile) can call 1.28 times
- Bottom quarter user (25th percentile) can call 0.03 times
- Average user can call 174.25 times
- Average (excluding top and bottom 1000) can call 30.38 times
Func "Burn"
- Func "Burn" average cost: 6,198,809 ugnot
- Median user (50th percentile) can call 1.35 times
- Bottom quarter user (25th percentile) can call 0.03 times
- Average user can call 184.83 times
- Average (excluding top and bottom 1000) can call 32.23 times
Func "Transfer"
- Func "Transfer" average cost: 8,212,674 ugnot
- Median user (50th percentile) can call 1.02 times
- Bottom quarter user (25th percentile) can call 0.02 times
- Average user can call 139.51 times
- Average (excluding top and bottom 1000) can call 24.33 times
Onbloc Research & Notes
Gno Transaction Fee Comparison in Devnet
- General Transfer:
- Fee: 0.000115 GNOT
- Used/Wanted: 47,066/55,015 (85.55%)
- Mint Transaction (GnoSwap):
- Fee: 0.405793 GNOT
- Used/Wanted: 162,318,280/194,780,448 (83.33%)
- The Mint transaction consumes about x3500 more fees than a general GNOT transfer transaction
- Even if the Mint transaction requires complex computation such as uint256, this gap is too large and seems abnormal.
- A simple direct swap (not a complex routed swap) consumes 0.251787 GNOT, Used/Wanted of (100,715,640/120,857,292 (83.33%).
Transaction Fee Comparison in Portal-loop
- General Transfer:
- Fee: 0.000114 GNOT
- Used/Wanted: 44,310/54,271 (81.65%)
- Deposit (r/demo/wugnot, a simple contract):
- Fee: 0.01727 GNOT
- Used/Wanted: 6,908,950/8,289,264 (83.35%)
- A simple contract use consumes x151 more gas than a general transfer.
- Realm Package: gno.land/r/demo/wugnot
- Function: Deposit
gnokey maketx call \
-pkgpath "gno.land/r/demo/wugnot" \
-func "Deposit" \
-send "1000ugnot" \
-gas-fee 1000000ugnot \
-gas-wanted 20000000 \
-broadcast \
-chainid dev \
test1
Gas consumption by item
description: ReadFlat , consumed: 10000
description: WriteFlat , consumed: 10000
description: WritePerByte , consumed: 17610
description: ante verify: secp256k1 , consumed: 1000
description: GetPackageRealmPerByte , consumed: 35632
description: SetObjectPerByte , consumed: 31360
description: txSize , consumed: 2510
description: ReadPerByte , consumed: 3522
description: GetObjectPerByte , consumed: 2668848
description: CPUCycles , consumed: 158313
description: SetPackageRealmPerByte , consumed: 35632
description: DeleteObjectFlat , consumed: 7430
- Gas consumption is about 89.5% being consumed by the item called GetObjectPerByte.
- Items that load the VM’s state objects
Consuming gas to load objects seems like a reasonable gas consumption.
However, the gas weight of GetObjectPerByte
is multiplied by 16
and is consuming a lot of gas.
I have a couple questions here.
I’ll have to track what is being loaded further, but is a weight of 16
appropriate?
Giuseppe / Milos gas fee message
Here is where we do the fee validation:
https://github.com/gnolang/gno/blob/6f91a35f3fcb0da593a8b45f6b19d70865406e05/tm2/pkg/sdk/auth/ante.go#L333-L406
The block gas context value is set in the app setup:
https://github.com/gnolang/gno/blob/6f91a35f3fcb0da593a8b45f6b19d70865406e05/gno.land/pkg/gnoland/app.go#L124-L125
the initial value of the block gas context (price) is set in the init chainer:
https://github.com/gnolang/gno/blob/6f91a35f3fcb0da593a8b45f6b19d70865406e05/gno.land/pkg/gnoland/app.go#L330-L331
this param value is set in the initial auth params:
https://github.com/gnolang/gno/blob/6f91a35f3fcb0da593a8b45f6b19d70865406e05/tm2/pkg/sdk/auth/params.go#L34 (by default it's 0.001ugnot/gas, it's part of the genesis state in genesis.json):
"auth": {
"params": {
"max_memo_bytes": "65536",
"tx_sig_limit": "7",
"tx_size_cost_per_byte": "10",
"sig_verify_cost_ed25519": "590",
"sig_verify_cost_secp256k1": "1000",
"gas_price_change_compressor": "10",
"target_gas_ratio": "70",
"initial_gasprice": {
"gas": "1000",
"price": "1ugnot"
}
}
}
This block-level gas price is updated in the EndBlocker logic:
https://github.com/gnolang/gno/blob/6f91a35f3fcb0da593a8b45f6b19d70865406e05/tm2/pkg/sdk/auth/keeper.go#L195-L205
The validators set the target gas ratio to move the minimum network gas fee up or down (check calcBlockGasPrice
).
This value is updated through the params keeper, which we can call through governance proposals in gno code
The node-specific gas limit is also set in the app setup (config.toml param):
https://github.com/gnolang/gno/blob/6f91a35f3fcb0da593a8b45f6b19d70865406e05/gno.land/pkg/gnoland/app.go#L88.
Node operators can update this at any time before they start their node
@Ray Qin can correct me if I missed something in haste, but this should be it:
- network (block) gas fee limits are controlled through governance (govdao), using the params module. Initial state set in genesis state
- validator (node) gas fee limits are set through the config.toml , and are node-specific