neo-project / neo

NEO Smart Economy
MIT License
3.46k stars 1.03k forks source link

Invocation GAS cost on dynamic contracts #2806

Open odd86 opened 2 years ago

odd86 commented 2 years ago

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

Where in the software does this update applies to?

roman-khimov commented 2 years ago

While the problem is well-known (#1536, #2443, #2448, https://github.com/neo-project/neo/issues/2568#issuecomment-899167753 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:

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:

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

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 commented 2 years ago

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 commented 2 years ago

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

roman-khimov commented 11 months ago

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.