Skip to content

Conversation

@xermicus
Copy link
Member

This PR adds two new syscalls for calls accepting EVM gas instead of Weight and Deposit.

This is an important change for the initial release as it will align PVM contracts closer to EVM (the problem can't be solved in the Solidity compiler).

@xermicus
Copy link
Member Author

/cmd fmt

Copy link
Contributor

@pgherveou pgherveou left a comment

Choose a reason for hiding this comment

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

Looks good at first glance
On my phone now will take a second look from laptop

@xermicus xermicus added R0-no-crate-publish-required The change does not require any crates to be re-published. T7-smart_contracts This PR/Issue is related to smart contracts. labels Nov 25, 2025
flags: u32,
callee: u32,
value_ptr: u32,
gas_ptr: u32,
Copy link
Contributor

Choose a reason for hiding this comment

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

shouldn't we pass gas as a u64?

Copy link
Member Author

Choose a reason for hiding this comment

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

Why u64? It would move the overflow check into contract code.

Copy link
Contributor

Choose a reason for hiding this comment

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

I was not thinking of solidity

the uapi would be nicer if it was just

  pub fn call_evm(
    flags: u32,
    callee: u32,
    value: u32,
    gas: u64,
    input_data: u64,
    output_data: u64,
  ) -> ReturnCode;

since gas is just a u64.

but then I guess since in revive you translate call instructions where the gas is a uint256 that would force you to do the overflow check in the contract

Copy link
Member Author

@xermicus xermicus Nov 25, 2025

Choose a reason for hiding this comment

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

Yeah the gas argument is an u256 (since it's the only int type in Yul).

However, actually considering it, an u64 probably wouldn't even be that bad. In many cases, the supplied gas is just what was returned from gas() or some constant value (address.transfer) - both cases don't need overflow checks (this is an optimization).

Such optimizations aren't planned for the initial resolc 1.0 release but easy to implement in the future. So I think it'd actually be helpful when this matches what gas_left returns, which is u64. Done right, I suspect that this will lead to LLVM itself to recognize and eliminate the overflow check - I'll test this to be sure (because then it's definitively favorable).

Thinking it further, we could also use a "no gas" API method for when the gas to use is what gas() returned. This would just use CallResources::NoLimits. Which could just be even be expressed by a sentinel pointer value. Probably fine to just us u64::max too, since this would mean uncapped resources anyways? Need to think about this.

Copy link
Contributor

Choose a reason for hiding this comment

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

All that make sense.

when I wrote the comment I was mostly thinking of the use case of someone writing a contract in Rust with the low-level API where there I think it make sense to use a u64.

Thinking it further, we could also use a "no gas" API method for when the gas to use is what gas() returned. This would just use CallResources::NoLimits. Which could just be even be expressed by a sentinel pointer value. Probably fine to just us u64::max too, since this would mean uncapped resources anyways? Need to think about this.

Yeah maybe in that case you call the regular call method with W(u64::max, u64::max) as it result in less math ops to compute the gas_left (@TorstenStueber might be better advisor here)

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah the new syscalls are specifically for resolc - with Rust contracts people are not bound to EVM gas and can use the existing syscalls using Weight and Deposit.

Regarding the uncapped calls. I think this depends if we implement the "63/64" rule. Even if we don't implement it exactly like on Ethereum: The contract can't just supply the absolute maximum, instead it needs to be able to express that the call should get whatever is left.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds all good.

Yeah maybe in that case you call the regular call method with W(u64::max, u64::max) as it result in less math ops to compute the gas_left (@TorstenStueber might be better advisor here)

CallResources::NoLimits is always the least overhead. If the transaction as a whole uses Ethereum execution mode (limited by gas), then any call to a subsequent frame won't be able to switch that mode to Substrate execution mode even if using W(u64::max, u64::max).

Regarding the uncapped calls. I think this depends if we implement the "63/64" rule. Even if we don't implement it exactly like on Ethereum: The contract can't just supply the absolute maximum, instead it needs to be able to express that the call should get whatever is left.

There is currently no such implementation itself. We can add a 63/64 later but the current logic is already complicated enough for the first iteration.

Copy link
Contributor

@pgherveou pgherveou Nov 27, 2025

Choose a reason for hiding this comment

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

Yeah the new syscalls are specifically for resolc - with Rust contracts people are not bound to EVM gas and can use the existing syscalls using Weight and Deposit.

However, actually considering it, an u64 probably wouldn't even be that bad. In many cases, the supplied gas is just what was returned from gas() or some constant value (address.transfer) - both cases don't need overflow checks (this is an optimization).

It's your call but If future compiler optimisation can optimize that away, picking the host call that use u64 might be interesting as well.

If we revisit the whole pallet-transaction-payment, and gas mapping integration to make gas the main metering unit (instead of it being derived from being fees / gas_price) then this could also become a nice api for Rust contract as well

Signed-off-by: xermicus <[email protected]>
@paritytech-workflow-stopper
Copy link

All GitHub workflows were cancelled due to failure one of the required jobs.
Failed workflow url: https://github.com/paritytech/polkadot-sdk/actions/runs/19677551141
Failed job name: cargo-clippy

Copy link
Contributor

@TorstenStueber TorstenStueber left a comment

Choose a reason for hiding this comment

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

Nice, I like it.

flags: u32,
callee: u32,
value_ptr: u32,
gas_ptr: u32,
Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds all good.

Yeah maybe in that case you call the regular call method with W(u64::max, u64::max) as it result in less math ops to compute the gas_left (@TorstenStueber might be better advisor here)

CallResources::NoLimits is always the least overhead. If the transaction as a whole uses Ethereum execution mode (limited by gas), then any call to a subsequent frame won't be able to switch that mode to Substrate execution mode even if using W(u64::max, u64::max).

Regarding the uncapped calls. I think this depends if we implement the "63/64" rule. Even if we don't implement it exactly like on Ethereum: The contract can't just supply the absolute maximum, instead it needs to be able to express that the call should get whatever is left.

There is currently no such implementation itself. We can add a 63/64 later but the current logic is already complicated enough for the first iteration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

R0-no-crate-publish-required The change does not require any crates to be re-published. T7-smart_contracts This PR/Issue is related to smart contracts.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants