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 resources to 63/64 on sub calls and remove 0 as special case for "take all" #6846

Open
athei opened this issue Dec 11, 2024 · 3 comments · May be fixed by #6890
Open

Limit resources to 63/64 on sub calls and remove 0 as special case for "take all" #6846

athei opened this issue Dec 11, 2024 · 3 comments · May be fixed by #6890
Assignees

Comments

@athei
Copy link
Member

athei commented Dec 11, 2024

As of right now when calling a sub contract on pallet_revive we allow the sub call to use up all the resources that the caller specifies that are allowed to be used. However, oh Eth this value is capped by 63/64 of the remaining gas. We want to do the same.

Especially, because Solidity will not be able to limit any other resource than ref_time. Limiting of all resources will be enabled by a pre-compile.

@athei athei converted this from a draft issue Dec 11, 2024
@rockbmb
Copy link
Contributor

rockbmb commented Dec 11, 2024

Hello! Can I help with this?

@athei athei changed the title Limit resources to 63/64 on sub calls Limit resources to 63/64 on sub calls and remove 0 as special case for "take all Dec 11, 2024
@athei athei changed the title Limit resources to 63/64 on sub calls and remove 0 as special case for "take all Limit resources to 63/64 on sub calls and remove 0 as special case for "take all" Dec 11, 2024
@athei
Copy link
Member Author

athei commented Dec 11, 2024

Yes. It should be a fairly small change to do. Basically, when we create the nested meter for the sub call we need to limit it by 63/64 of the remaining gas:

.min(self.gas_left);

Same for the storage meter:

pub fn nested(&self, limit: BalanceOf<T>) -> RawMeter<T, E, Nested> {
debug_assert!(matches!(self.contract_state(), ContractState::Alive));
// If a special limit is specified higher than it is available,
// we want to enforce the lesser limit to the nested meter, to fail in the sub-call.
let limit = self.available().min(limit);
if limit.is_zero() {
RawMeter { limit: self.available(), ..Default::default() }
} else {
RawMeter { limit, nested: Nested::OwnLimit, ..Default::default() }
}
}

But please first verify first if it is really 63/64 by checking geth source code (its easy the have one filer per op code).

I also extended the issue (see title) by another thing because I think it is connected: Right now passing 0 as resource value means "take all". This isn't good because we cannot express limiting the resource to 0 as this can make sense in certain cases. Please get rid of this special case (for both meters) and just treat it as "no resource usage allowed". Take all is already accurately represented by just passing a u64::MAX as we are limiting the value anyways to what is available.

@rockbmb
Copy link
Contributor

rockbmb commented Dec 12, 2024

But please first verify first if it is really 63/64 by checking geth source code (its easy the have one filer per op code).

I was unaware of this mechanism in Ethereum, so I looked it up - https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md

I've searched at https://github.com/ethereum/go-ethereum to confirm the 63/64 value, as you suggested.

In go-ethereum/core/vm/gas_table.go, I see

  1. func gasCall
  2. func gasCallCode
  3. func gasDelegateCall
  4. func gasStaticCall
  5. func gasSelfdestruct

All of the above have a evm.chainRules.IsEIP150 check, which when enabled, alters the behavior of func callGas for functions 1.-4., and for gasSelfdestruct, alters the cost of SELFDESTRUCT from 0 (pre-EIP150) to 5000.

func callGas is similar to fn nested you linked, since it determines callGasTemp, in each function 1. through 4.:

	// callGasTemp holds the gas available for the current call. This is needed because the
	// available gas is calculated in gasCall* according to the 63/64 rule and later
	// applied in opCall*.
	callGasTemp uint64

TL;DR 63/64 is still the number to use.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Minimal Feature Launch
Development

Successfully merging a pull request may close this issue.

2 participants