Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Package calls + deployments cost a fixed number of ugnot #649

Closed
zivkovicmilos opened this issue Mar 25, 2023 · 5 comments
Closed

Package calls + deployments cost a fixed number of ugnot #649

zivkovicmilos opened this issue Mar 25, 2023 · 5 comments
Labels
good first issue Good for newcomers help wanted Extra attention is needed tokenomics

Comments

@zivkovicmilos
Copy link
Member

Description

This issue is meant to start a discussion on how we can improve the pricing model for package calls and deployments, as they currently cost a fixed 1000000ugnot:

These fees should probably be outlined somewhere so users are aware of them upfront

@zivkovicmilos zivkovicmilos added good first issue Good for newcomers help wanted Extra attention is needed labels Mar 25, 2023
@nir1218
Copy link
Contributor

nir1218 commented Mar 29, 2023

@zivkovicmilos
One option is to set cost per byte. Assume the cost per byte is set to 1ugnot, and the message length is 100000, the total cost will be 100000ugnot.

Another option is to set a percentage amount from the deposit/coins sent in the message.

@grepsuzette
Copy link
Contributor

grepsuzette commented Mar 30, 2023

Not directly answering anything but I a question about fees:

Suppose a package do involved stuffs, or maybe the complexity of an algo is bad.

Does gno currently have mechanism(s) to limit the actual resources used in that case and when it's not a transaction? (because then supposedly, fee=0, does my question make sense? In essence I am asking if the VM will refuse to work after some maximum mileage has been done for free).

(edit: I guess that would be gas like on other blockchains, so I suppose gno also has it :p).

@thehowl
Copy link
Member

thehowl commented Jul 5, 2023

I think the fee for call should probably be something like $c + k \Delta m$, c = vm cpu cycles, $\Delta m$ = difference in persisted data (after compression?) in bytes, with k being a value that puts in relation memory to cpu cycles.

I like the idea that in the future, the economic value of a single ugnot should roughly match the economic cost of doing 1 gnovm cycle (= an infinitesimal amount of USD). As for the value of k, I think it's very very tricky. It's essentially the cost of storing 1 byte of data for ""eternity"" with potentially infinite replication, which from a theoretical point of view is probably on the order of a few thousand dollars, but for practical terms this should be closer to something like 1 USD = 10kb (the core idea being, if we are to have social platforms like a twitter clone on Gno, my yearly cost for participating shouldn't be more than 4$). But really, I think it should be much more expensive than VM cycles (storing data is expensive, verifying a transaction is comparatively cheap) and it needs to be defined after we give full answers to questions like "what do we do when the size of all transactions reaches 100TB?".

One other thing is that counting bytes when doing addpkg creates an incentive to write smaller packages with less code. Which leads to obfuscation, short variable names, no comments. Which is why I think that it makes sense for addpkg to instead count the number of AST nodes, for instance, instead of rough code size.

There should then also probably be a fixed fee for storing a single transaction, call it "overhead", but roughly still $k\Delta m$ given by the amount of bytes we require to store tx data.


@grepsuzette "free" operations (like qeval, qrender) should have some form of limit. Transactions have gas (mem allocations + cpu cycles), public operations which are not transactions should probably be either removed before mainnet or limited in some way for safety. (ie. rate-limit cycles/allocs per ip per hour, make them in general low-priority so that blockchain TXs are executed first). Right now the only limit is vm.maxCycles, I guess.

Seeing as they are executed on a single node and it's not data that is propagated to other nodes, we could even make it that nodes can disable public calls entirely (including qrender, which is used for gnoweb). A bit extreme, but definitely creates some security against DoS attacks.

@MichaelFrazzy
Copy link

MichaelFrazzy commented Jul 5, 2023

I think the fee for call should probably be something like c+kΔm, c = vm cpu cycles, Δm = difference in persisted data (after compression?) in bytes, with k being a value that puts in relation memory to cpu cycles.

I like the idea that in the future, the economic value of a single ugnot should roughly match the economic cost of doing 1 gnovm cycle (= an infinitesimal amount of USD). As for the value of k, I think it's very very tricky. It's essentially the cost of storing 1 byte of data for ""eternity"" with potentially infinite replication, which from a theoretical point of view is probably on the order of a few thousand dollars, but for practical terms this should be closer to something like 1 USD = 10kb (the core idea being, if we are to have social platforms like a twitter clone on Gno, my yearly cost for participating shouldn't be more than 4$). But really, I think it should be much more expensive than VM cycles (storing data is expensive, verifying a transaction is comparatively cheap) and it needs to be defined after we give full answers to questions like "what do we do when the size of all transactions reaches 100TB?".

One other thing is that counting bytes when doing addpkg creates an incentive to write smaller packages with less code. Which leads to obfuscation, short variable names, no comments. Which is why I think that it makes sense for addpkg to instead count the number of AST nodes, for instance, instead of rough code size.

There should then also probably be a fixed fee for storing a single transaction, call it "overhead", but roughly still kΔm given by the amount of bytes we require to store tx data.

@grepsuzette "free" operations (like qeval, qrender) should have some form of limit. Transactions have gas (mem allocations + cpu cycles), public operations which are not transactions should probably be either removed before mainnet or limited in some way for safety. (ie. rate-limit cycles/allocs per ip per hour, make them in general low-priority so that blockchain TXs are executed first). Right now the only limit is vm.maxCycles, I guess.

Seeing as they are executed on a single node and it's not data that is propagated to other nodes, we could even make it that nodes can disable public calls entirely (including qrender, which is used for gnoweb). A bit extreme, but definitely creates some security against DoS attacks.

I love these ideas and the equation as a starting point. Will dig in more here after wrapping up another doc, for now I have some initial thoughts on how we can further improve the equation to bounce around!

I think using a logistic relationship between delta m and the fee instead of linear should be considered. Potentially exponential if we don't want there to be an upper bound/limit for fees, but if we set the top of the logistic curve high enough... an upper bound (logistic) is probably preferable overall. Logistic will also be easier to test vs expo, since we can define an upper fee bound and then I can model different coefficients to control how quickly it reaches that cap before I stress test the final version. Another nice side effect is it results in a slow fee ramp up when the network isn't as congested, with extreme fee increases only after a certain threshold we can set. I can start drafting up some different logistic equations that can be added within the existing equation, for now just to see how it plays out. Would be curious to see if CPU cycles themselves are more linear or logistic in nature as they ramp up.

Probably worth brainstorming dynamic k range ideas instead of a fixed value too, I think your concerns are spot on when it comes to defining an exact value there. We could talk through some sliding scale ideas here based on transaction rate, block fullness, or whatever network metric is deemed the best overall while not being crazy to implement.

A couple questions as well, do we want a feature where similar to EVM you can pay extra fees to prioritize your transaction and speed up how quickly it's processed? So adding a time variable into the equation with most transactions using a base time value we'd define for normal transactions that aren't expedited? And will certain transactions have the ability to work similarly to signing a message on ETH (for free)? Think when casting a snapshot vote, signing a multi-sig, or something else where no gas is required. What comes to mind here is some of the social media applications (maybe with a subscription fee model), certain voting actions, etc. Then anything free we could limit per amount of time or per number of blocks to prevent spam for these particular operations, if it's possible to implement in the first place.

@moul moul added the tokenomics label Jul 6, 2023
@moul moul added this to the 🚀 main.gno.land milestone Sep 6, 2023
piux2 added a commit that referenced this issue Apr 25, 2024
<!-- please provide a detailed description of the changes made in this
pull request. -->

<details><summary>Contributors' checklist...</summary>

- [x] Added new tests
- [ ] Provided an example (e.g. screenshot) to aid review or the PR is
self-explanatory
- [ ] Updated the official documentation or not needed
- [x] No breaking changes were made
- [x] Added references to related issues and PRs
- [ ] Provided any useful hints for running manual tests
- [ ] Added new benchmarks to [generated
graphs](https://gnoland.github.io/benchmarks), if any. More info
[here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
</details>

Ref: #1070 #1067 #649 #1281 


## Summary

The current gno.land node, optimized for development purposes, has a
simplified verification process and gas meter implementation. To
transition the gno.land node to a production-ready state, it is
necessary to implement a comprehensive gas metering system that
accurately accounts for VM gas consumption. This includes refining the
gas fee structure to encompass all relevant costs, ensuring robust
transaction validation, and calculating gas consumption based on actual
computational load.

This PR aims to address these limitations by introducing a complete gas
meter and validation flow, laying the groundwork for further gas meter
profiling and configuration.


## Problem Definition

Current State and Limitations for Production:

- **VM Gas Consumption Not Accounted in Gas Meter:** The current gas
meter fails to calculate VM gas consumption, potentially allowing heavy
contract loads without corresponding gas meter deductions. A refined
system should measure and charge for VM gas usage accurately.

- **Gas Fee Structure:** Presently, the gas fee structure only includes
storage access, transaction size, and signature verification. VM gas
fees are levied as a separate, flat fee, which might lead to confusion
among users expecting the total fee to match the amount specified in the
'gas-fee' argument. For improved transparency and precision, the gas fee
structure should integrate all these aspects.

- **Transaction Validation:** The system currently validates basic
information for VM msg_addpkg and msg_call. However, gas consumption
cannot be determined before fully executing these messages against the
VM. Consequently, VM transactions are placed in the mempool and
propagated to other nodes, even if they may not meet the gas fee
requirements to execute these transactions. This undermines the purpose
of using gas fees to prevent VM spamming.


## Solution: ( Updated )
This is a high-level description of the implemented features:

~~Added an anteHandler in VM to monitor gas consumption~~
~~Implemented chained VM anteHandler in auth.anteHandler~~
- Consume gas to verify account, signature and tx size in CheckTx 
- Consume VM gas in DeliverTx 
- Accumulated VM CPU cycles, memory allocation, store access,
transaction size, and signature verification into a single gas meter.
- Enabled local node checks of VM resource usage. The VM message is only
aborted if it runs out of gas in basic CheckTx. However, the message is
still propagated to other nodes if execution fails to prevent censorship
- Introduced a structured format for logging gas consumption for
profiling and metrics.
- Introduced a gas factor linking gas to vm CPU cycles and memory
allocation to balance between vm gas consumption with the rest.



## Trade-offs and Future Optimization: ( Updated )
~~The current implementation processes messages against the VM to check
gas consumption in abci.CheckTx() before inclusion in the mempool and
propagation to other nodes.~~

~~Messages lacking sufficient gas-wanted will be dropped, preventing
abuse without adequate gas fees. However, the trade-off is that for each
message with enough gas, the VM executes the transaction twice: once in
CheckTx() and once in DeliverTx(). As these occur in separate execution
contexts and are not in synchronized sequence, the performance impact is
currently a secondary concern.~~

We moved the VM gas check from CheckTx to DeliverTx for the following
reasons:

- We only know the VM gas consumption after the messages have been
processed.
- Running VM execution for many CheckTx requests from the peers could
overload the mempool that is executing CheckTx.
- This could slow down the propagation of transactions across the entire
network.

By moving the VM gas check from CheckTx to DeliverTx, we are able to
reduce the load on the mempool of a node and allow transactions to
propagate through the network faster.

In the future, we may use a predicted median value instead of the exact
value from transaction execution for efficiency.

## What's Next:
- Add a minimum gas price flag and configuration for node operation.
- Provide a user-friendly fee input interface, offering 'gas-wanted' and
'gas price' as alternatives to the current 'gas-wanted' and 'gas-fee'
inputs.
- Tune the gas factor based on VM CPU and Memory Profiling. The current
factor is 1:1 between gas and VM CPU cycles and memory allocation.

---------

Co-authored-by: Thomas Bruyelle <thomas.bruyelle@gmail.com>
@zivkovicmilos
Copy link
Member Author

This fixed pricing was removed as part of #1430, closing this issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers help wanted Extra attention is needed tokenomics
Projects
Status: Done
Status: 🚀 Needed for Launch
Development

No branches or pull requests

6 participants