Skip to content

Conversation

@ARR4N
Copy link
Collaborator

@ARR4N ARR4N commented Sep 26, 2024

Why this should be merged

Allow stateful precompiles to call other contracts; e.g. for ava-labs/coreth's NativeAssetCall.

How this works

The vm.PrecompileEnvironment.Call() method is added to mirror vm.EVM.Call() in behaviour and in all syntax except the first argument, caller—the caller is the precompile itself, which is deterministic. An option to override the caller is included for backwards compatibility with NativeAssetCall but it MUST NOT otherwise be used.

Determining the correct ContractRef to use as the caller uncovered existing bugs in the libevm.AddressContext values passed to the precompile. Specifically, the Self and Caller addresses under CallCode() and DelegateCall() invocation of the precompile were incorrect. These are fixed via a refactor to abstract env behaviour into a new environment type although most of this is existing code just in a new file. Note that this fix means that stateful precompiles now behave as Solidity developers expect (other than #41).

The evmCallArgs field for read-write inheritance is replaced with a call-type field that indicates the EVM method through which the precompile was invoked. This implies RW inheritance (i.e. StaticCall() vs not) while also allowing other behaviour and simplifying the construction of an evmCallArgs.

How this was tested

An integration test exercises typical behaviour of a precompile calling another contract: origin (EOA) -> regular bytecode contract -> precompile -> any other contract. This demonstrates plumbing of data as well as correct setting of the caller.

The existing test of new precompiles is updated to demonstrate the fix of the AddressContext values.

//
// ****** SECURITY ******

var _ PrecompileEnvironment = (*evmCallArgs)(nil)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

These have all been moved to the new environment type in environment.libevm.go.

return e.callContract(call, addr, input, gas, value, opts...)
}

func (e *environment) callContract(typ callType, addr common.Address, input []byte, gas uint64, value *uint256.Int, opts ...CallOption) ([]byte, uint64, error) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This function is the primary implementation of the PR. Everything else was a necessary refactor to fix the Caller and Self addresses for the incoming call types.

@ARR4N ARR4N marked this pull request as ready for review September 30, 2024 08:58
@ARR4N ARR4N requested review from a team, ceyonur, darioush and michaelkaplan13 and removed request for a team September 30, 2024 09:11
@ARR4N ARR4N merged commit 210f8ab into libevm Sep 30, 2024
3 checks passed
@ARR4N ARR4N deleted the arr4n/precompile-env-evm-call branch September 30, 2024 16:26
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.

2 participants