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

Limit Refuel to 1 GAS #2561

Closed
wants to merge 10 commits into from
Closed

Limit Refuel to 1 GAS #2561

wants to merge 10 commits into from

Conversation

erikzhang
Copy link
Member

No description provided.

@erikzhang
Copy link
Member Author

@shargon @roman-khimov What do you think?

@shargon
Copy link
Member

shargon commented Aug 4, 2021

I think that if the account it's related to any transaction in the block, and it remove the total gas can poduce a Denial of service during onPersist, I agree with @roman-khimov in ABORT

@ZhangTao1596
Copy link
Contributor

Attackers can call refuel multi times to occupy system resource.

@erikzhang erikzhang closed this Aug 4, 2021
@erikzhang erikzhang deleted the limit_refuel branch August 4, 2021 08:14
@ZhangTao1596
Copy link
Contributor

Limit sum of refueled gas to 1 gas?

@shargon
Copy link
Member

shargon commented Aug 4, 2021

Limit Refuel to only one call per invocation

@erikzhang erikzhang restored the limit_refuel branch August 4, 2021 08:29
@ZhangTao1596
Copy link
Contributor

How about this #2563

@erikzhang erikzhang reopened this Aug 4, 2021
@erikzhang
Copy link
Member Author

@roman-khimov What do you think?

@erikzhang
Copy link
Member Author

Can anyone fix the UT?

shargon
shargon previously approved these changes Aug 4, 2021
@shargon shargon self-requested a review August 4, 2021 08:51
@shargon
Copy link
Member

shargon commented Aug 4, 2021

Can anyone fix the UT?

I will

shargon
shargon previously approved these changes Aug 4, 2021
@shargon
Copy link
Member

shargon commented Aug 4, 2021

@superboyiii could you test it if it could produce a DoS if during onPersist we remove the gas from other transaction fee?

@roman-khimov
Copy link
Contributor

@roman-khimov What do you think?

  1. It's very limiting.
  2. It doesn't solve the problem.

ABORT is still there to make node's computational efforts almost free, so amplification is still possible.

@erikzhang
Copy link
Member Author

Another protection mechanism can also be introduced: we can only allow Refuel calls from contracts. In this way, if the function is abused, we can sanction the contracts in the future.

@superboyiii
Copy link
Member

@roman-khimov What do you think?

  1. It's very limiting.
  2. It doesn't solve the problem.

ABORT is still there to make node's computational efforts almost free, so amplification is still possible.

I agree with Roman. ABORT now and think for better solution later. It's too hurry find another way which might cause other issue.

@shargon
Copy link
Member

shargon commented Aug 4, 2021

Or can we even require the contract to pay for Refuel in advance?

Too much better

@chenzhitong
Copy link
Member

Pay GAS in advance and refund the remaining system fee to the user. (No refund if an exception occurs)

@erikzhang
Copy link
Member Author

I have another idea. We can limit it to tx.SystemFee + tx.NetworkFee. What do you think?

@roman-khimov
Copy link
Contributor

  1. Even more limiting, making Refuel less and less practical.
  2. Limits amplification factor to 2. Not a lot, true, but still amplification.

@erikzhang
Copy link
Member Author

Even more limiting, making Refuel less and less practical.

I think it's better than removing it.

Limits amplification factor to 2. Not a lot, true, but still amplification.

If we limit it to tx.SystemFee + tx.NetworkFee, I'm sure no one will attack this way again.

@shargon
Copy link
Member

shargon commented Aug 4, 2021

Pay gas in advance, make a bag, and decrement this bag during refuel, like this never can affect to OnPersist

@@ -40,10 +40,12 @@ internal override async ContractTask OnPersist(ApplicationEngine engine)
[ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)]
private async ContractTask Refuel(ApplicationEngine engine, UInt160 account, long amount)
{
if (amount < 0) throw new ArgumentOutOfRangeException(nameof(amount));
if (amount <= 0) throw new ArgumentOutOfRangeException(nameof(amount));
if (ContractManagement.GetContract(engine.Snapshot, engine.CallingScriptHash) is null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Account?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean?

Copy link
Member

@shargon shargon Aug 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who pay te gas it's the account argument

@erikzhang
Copy link
Member Author

I think it's perfect now.

@chenzhitong
Copy link
Member

UT

@roman-khimov
Copy link
Contributor

Even more limiting, making Refuel less and less practical.

I think it's better than removing it.

The intention behind #2444 can be traced via #2443 to neo-project/proposals#137 and that intention to me is to have contract-sponsored actions. Limiting Refuel to fee amount makes the user inevitably pay half of the real price, so it's a discount, but the intention was rather to have contract paying 90%+ of fees. I've questioned usefulness of this method already in #2443 (from a bit different perspective though), but with this limit it's hard for me to imagine who is going to use it. Methods should solve some problems and I'm not sure it solves anything now.

@erikzhang
Copy link
Member Author

It is difficult for a contract to determine whether the sponsorship has been abused. Now it does not need to worry too much, because users have to pay at least half of the cost.

@erikzhang
Copy link
Member Author

but the intention was rather to have contract paying 90%+ of fees

Maybe we can limit it to 10 * (tx.SystemFee + tx.NetworkFee)?

@ZhangTao1596
Copy link
Contributor

ZhangTao1596 commented Aug 4, 2021

Maybe we can limit it to 10 * (tx.SystemFee + tx.NetworkFee)

(tx.SystemFee + tx.NetworkFee) * execFactor / 3?

@superboyiii
Copy link
Member

superboyiii commented Aug 4, 2021

but the intention was rather to have contract paying 90%+ of fees

Maybe we can limit it to 10 * (tx.SystemFee + tx.NetworkFee)?

I think system_fee + = Refuel /exe_Factor*3 is more resonable. Don't make a static limit to a dynamic result.

@roman-khimov
Copy link
Contributor

Maybe we can limit it to 10 * (tx.SystemFee + tx.NetworkFee)?

Increases usefulness, raises amplification factor.

Don't make a static limit to a dynamic result.

ExecFeeFactor is already priced-in with system fee.

@roman-khimov
Copy link
Contributor

roman-khimov commented Aug 4, 2021

Pay gas in advance, make a bag, and decrement this bag during refuel, like this never can affect to OnPersist

And BTW, while this probably is the only valid solution (if not counting Refuel deletion) it would also mean that execution will produce some side-effect for failed transaction which was never the case before (fees written off is a bit different story).

Which technically allows to attack contract itself (draining balance from it), so maybe it's not a valid solution either.

@roman-khimov
Copy link
Contributor

As a side note, think of MaxBlockSystemFee also that Refuel technically breaks. Not the biggest problem with it, but still.

@ZhangTao1596
Copy link
Contributor

We should revert first. Seems we can't get agreement soon.

@igormcoelho
Copy link
Contributor

igormcoelho commented Aug 5, 2021

For this Refuel to work we need to make sure that the assets are innevitably taken from user or contract account. It should have similar logic to network or system fees, so relating a factor into it is a clever solution, that only introduces a price reduction, at worst.

For the moment, I agree with @erikzhang in putting a limiting factor of 2, or even zero, if necessary. Best thing if we could put it in some global constant, that can be updated on time. Then, we take the time to discuss it further.

I also agree to take funds only from a deployed contract.
In my opinion, nodes can calculate how much refunds are being done from a contract (including FAULT ones), and if it reaches some threshold, Refuel gets disabled for that contract. It means that contracts willing to sponsor anything should be careful to only authorize only effective transactions.

@ZhangTao1596
Copy link
Contributor

ZhangTao1596 commented Aug 5, 2021

Another problem. Once we set the limit inApplicationEngine, we have to keep it there and add height check when we apply new refuel mechanism in the future. Because old tx can't be executed in new mechanism.

@erikzhang erikzhang closed this Aug 5, 2021
@erikzhang erikzhang deleted the limit_refuel branch August 5, 2021 05:05
roman-khimov added a commit to nspcc-dev/neo-go that referenced this pull request Aug 5, 2021
It can be used to attack the network (amplifying DOS), so it's broken
beyond repair. See also neo-project/neo#2560 and neo-project/neo#2561.
roman-khimov added a commit to nspcc-dev/neo-go that referenced this pull request Aug 5, 2021
It can be used to attack the network (amplifying DOS), so it's broken
beyond repair. This reverts ac60160.

See also neo-project/neo#2560 and neo-project/neo#2561.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants