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

Invocation GAS cost on dynamic contracts #2806

Open
odd86 opened this issue Aug 19, 2022 · 4 comments
Open

Invocation GAS cost on dynamic contracts #2806

odd86 opened this issue Aug 19, 2022 · 4 comments
Labels
Discussion Initial issue state - proposed but not yet accepted
Milestone

Comments

@odd86
Copy link

odd86 commented Aug 19, 2022

Summary or problem description
With the current way of calculating GAS, (I think) Neo has a significant disadvantage when adoption finally comes. Neo VM is very strict when it comes to to little GAS sent in and if multiple users do advanced invocations or contracts with randomness, it's likely that the transaction will fail on the chain with an Insufficient GAS message.

This is not a problem for static contracts but a huge problem for dynamic contracts or contracts that has randomness.

The way to solve this today is to add an extra sys fee in the wallet invocation, which makes it more expensive for the user. It is still not safe as it can still fail in times of traffic spikes.

We do this for Flamingo Orderbook (add GAS, so at least ten people can trade at once), but in most cases, when the traffic is low, users pay 2x GAS cost but it's the only way for us to make sure that ten people can trade at once.

Today it can feel a bit like traveling on a toll road that has a high traffic fee of 1 USD and after paying the regular toll of 5 USD you are still denied access since you did not have the last 1 USD. This makes it so you need to go back to get more money and hope that this time you have enough.

Do you have any solution you want to propose?
Let contracts have a parameter of how much GAS they require to run. As a contract developer, you input a parameter saying that you want the wallet to have at least 1 GAS; after contract execution, it's the real GAS fee that is deducted from the user's wallet (not burn everything as it is now). This can be viewed as a gasLimit and will make sure that the invocation doesn't fail unless it costs more than the parameter. This will also make it easier for the users to know the expected cost of an invocation, and if you only used 0.1 GAS it's viewed as a bonus.

Neo Version

  • Neo 3

Where in the software does this update applies to?

  • VM
  • Contracts
@odd86 odd86 added the Discussion Initial issue state - proposed but not yet accepted label Aug 19, 2022
@roman-khimov
Copy link
Contributor

While the problem is well-known (#1536, #2443, #2448, #2568 (comment) and probably other) I don't think it's possible to solve it this way:

As a contract developer, you input a parameter saying that you want the wallet to have at least 1 GAS; after contract execution, it's the real GAS fee that is deducted from the user's wallet (not burn everything as it is now).

The problem is that we need to guarantee fee payment and current scheme does that by ensuring senders have enough GAS for all fees of all their mempooled transactions and deducting these fees before any in-block transactions are executed, right in the block context with OnPersist trigger. I don't think this can be changed and your scheme has at least the same problem that was the reason for #2444 removal of Refuel call.

I also don't think we can make better predictions in general case (like #2448), the exact state that will be used at transaction execution time is unknown and transaction executes Turing-complete code, it can use any amount of GAS. But the degree of this uncertainty is different from one use case to another. NEO transfers between simple accounts are very predictable. Flamingo order book functionality seems to be not so much, so you have to add some additional GAS "just in case" and to me it's inevitable.

However, we know the exact real amount of GAS spent after transaction execution and what can be done theoretically is refunding the difference (#1536). It at the same time is not so trivial as it sounds, because:

  • it's a state change, so there has to be some execution context that will do that
  • doing this in transaction's context is inappropriate, that's not what transaction's script does
  • doing this in PostPersist block context seems to be more viable
  • except C# node doesn't store the gas amount spent during the execution (ApplicationLog plugin does that, but that's plugin, while what's needed is something like TransactionState to store it)
  • so it just doesn't know what amount of GAS can be returned to the sender
  • and of course doing this changes the game seriously, adding some processing overhead and raising backwards compatibility question

But IMO ignoring this problem is not an option long-term, it does happen again and again leading to bad user experience (we also have #1982 which is related). What I'd do here is going #1536 route, but via a transaction attribute. We can't change the history for old transactions and there is a least one additional technical problem in the way, so doing it with attribute seems to be more appropriate.

The attribute (let's call it RefundableSystemFee) will work as follows:

  • it can be used only by non-contract senders (important! to be explained below)
  • it should be paid for (additional processing overhead is associated with it), for example 0.1 GAS per transaction (controlled via Policy contract)
  • GAS contract in PostPersist context will walk through transactions in the current block and mint SystemFee - GasConsumed to senders of transactions with this attribute

Unfortunately, contract senders can't safely use this attribute because refunding to them would require

  • either running onNEP17Payment handler in the PostPersist block context, and it's just not safe
  • or ignoring onNEP17Payment handler (not running it), but this breaks NEP-17 assumptions

Of course this will still require some way for GAS contract to get this GasConsumed data, so probably some TransactionState extension will be required along with an additional Ledger contract method maybe. Still, I think it can be done this way and frankly I don't see many other options. It's not trivial though and maybe that's why we still have this issue at all.

@odd86
Copy link
Author

odd86 commented Aug 19, 2022

Thanks a lot for this thorough answer!
I'm not the expert in this field on how its best solved or how to solve it, but I know that this is something that should be solved if we want the Smart Economy to actually be smart and not static 😅

I can only see this from 2 sides (as I'm not a core dev), and that is as a developer and as a user.

As a user, I would expect Neo to handle this as I should not lose money on state change that gives me insufficient gas (if I have enough in my wallet, of course) I would expect the VM to be smart enough to handle this as it will only give me double or triple costs to invoke again and hope I'm alone (not talking about Network fee)

As a developer, I would expect Neo VM to be smart enough, so my users did not end up with a bad experience in my advanced contracts. As a developer, I'm now "afraid" that more than one users use the contract at the same time, and that is why everyone now pays 2x fees; it feels unnecessary and also expensive, and I'm afraid that my product can't scale on Neo. (Personally not scared about it as I think we can solve this 😉)

The two token systems have very lovely advantages, but we must also acknowledge the drawbacks and try to iron them out as much as possible to help adoption, but we can talk more about that in a different thread 🤓

@Jim8y
Copy link
Contributor

Jim8y commented Aug 19, 2022

How about sending those extra fees into a contract and allowing users to claim them? Well, a temporary solution, of course.

@roman-khimov
Copy link
Contributor

How about sending those extra fees into a contract and allowing users to claim them? Well, a temporary solution, of course.

This can be a solution for contract-based senders, btw. Likely GAS contract fits well to provide this claiming functionality.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Discussion Initial issue state - proposed but not yet accepted
Projects
None yet
Development

No branches or pull requests

3 participants