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

feat: read-only stateful precompiles #20

Merged
merged 8 commits into from
Sep 14, 2024
Merged

Conversation

ARR4N
Copy link
Collaborator

@ARR4N ARR4N commented Sep 13, 2024

Why this should be merged

Adds support for signalling to a stateful precompile that it's running in a read-only context.

How this works

The vm.PrecompiledStatefulRun function signature was becoming bloated so everything except for input []byte has been collapsed into a vm.PrecompileEnvironment. Using a single argument also means that future features won't be breaking changes. A ReadOnly() bool method is available from the env. I called it an environment and not a context so that the idiomatic variable name can be env and not ctx.

Both a StateDB() vm.StateDB and a ReadOnlyState() libevm.StateReader are available from an env. The read-only version never returns nil while the full StateDB() method returns a non-nil state iff not in a read-only state (i.e. when ReadOnly() returns false). Without this, it would be too easy for a precompile implementation to forget to check ReadOnly() before writing to state.

How this was tested

A precompile is in a read-only state when there is at least one STATICCALL in the callstack that led to it being run. This can happen when either (a) there is a direct vm.EVM.StaticCall() to the precompile or; (b) there is a StaticCall() to some other contract that later calls the precompile via any *CALL* op code.

Scenario (a) is tested by extending the existing TestNewStatefulPrecompile test. Scenario (b) is more complex but thoroughly documented in TestPrecompileFromReadOnlyState.

@ARR4N ARR4N marked this pull request as ready for review September 13, 2024 13:02
@ARR4N ARR4N requested review from a team, darioush, ceyonur and michaelkaplan13 and removed request for a team September 13, 2024 13:02
Copy link
Collaborator

@darioush darioush left a comment

Choose a reason for hiding this comment

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

Pretty sure this is OK, it will force the precompiles to have to decide when they are using read-only vs modifying state but that seems a minor change + good for safety to me.

core/vm/evm.go Outdated Show resolved Hide resolved
@@ -69,6 +80,69 @@ func (p statefulPrecompile) Run([]byte) ([]byte, error) {
panic(fmt.Sprintf("BUG: call to %T.Run(); MUST call %T", p, p.run))
}

// A PrecompileEnvironment provides information about the context in which a
// precompiled contract is being run.
type PrecompileEnvironment interface {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Question: in general is it preferable to define interfaces like this (no param getters) or to have a struct like:

Suggested change
type PrecompileEnvironment interface {
type PrecompileEnvironment struct {
Rules params.Rules
ReadOnly bool
StateDB StateDB
ReadOnlyState libevm.StateReader
Addresses *libevm.AddressContext
}

Copy link
Collaborator Author

@ARR4N ARR4N Sep 14, 2024

Choose a reason for hiding this comment

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

Leaving this unresolved to reply to it later because it's a nuanced answer.

@ARR4N
Copy link
Collaborator Author

ARR4N commented Sep 14, 2024

Pretty sure this is OK, it will force the precompiles to have to decide when they are using read-only vs modifying state but that seems a minor change + good for safety to me.

That was entirely by design. I figured that since there would already be read-only checks that would have to be refactored to use the env that the refactor of the stateDB variable could be conditioned on that since it too would have to change. There shouldn't be any need to change the rest of the code (assuming it assigns the DB to a variable) since the methods are identical between StateDB and StateReader interfaces.

@ARR4N ARR4N merged commit 58f3883 into libevm Sep 14, 2024
3 checks passed
@ARR4N ARR4N deleted the arr4n/precompile-call-env branch September 14, 2024 09:45
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