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: vm.JumpTable override #30

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open

feat: vm.JumpTable override #30

wants to merge 22 commits into from

Conversation

ARR4N
Copy link
Collaborator

@ARR4N ARR4N commented Sep 17, 2024

Why this should be merged

Allows for creation of unexported vm.operations and their injection into vm.JumpTables through a registered hook.

First step to full support of #22.

How this works

Introduces vm.Hooks that can be registered via vm.RegisterHooks(). These are far simpler than params hooks as they don't need payloads. The vm.Hooks.OverrideJumpTable() hook is used in both NewEVMInterpreter() and LookupInstructionSet() to modify their respective JumpTables after creation. This couldn't be defined on params.RulesHooks due to a circular dependency.

The vm.OperationBuilder factory is also introduced to allow creation of the otherwise unexported operation type. I chose this pattern over a function because it makes arguments clearer at the usage site. To provide access to internal identifiers, the custom OperationFunc is an extension of the regular executionFunc to also accept an OperationEnvironment (similar to a PrecompileEnvironment).

How this was tested

Integration tests that demonstrate (a) honouring of the params hook signal; and (b) proper execution of a newly created *operation.

@ARR4N ARR4N marked this pull request as ready for review September 17, 2024 20:34
@ARR4N ARR4N requested review from a team, darioush, ceyonur and michaelkaplan13 and removed request for a team September 17, 2024 20:43
@ARR4N ARR4N marked this pull request as draft September 18, 2024 14:03
@ARR4N ARR4N marked this pull request as ready for review September 18, 2024 14:11

package vm

// An OperationBuilder is a factory for a new operations to include in a
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
// An OperationBuilder is a factory for a new operations to include in a
// An OperationBuilder is a factory for new operations to include in a

Comment on lines +27 to +32
func LookupInstructionSet(rules params.Rules) (jt JumpTable, err error) {
defer func() {
if err == nil { // NOTE `err ==` NOT !=
jt = *overrideJumpTable(rules, &jt)
}
}()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice defer to lower diffs with base repo 😉 !

Comment on lines +79 to +82
func overrideJumpTable(r params.Rules, jt *JumpTable) *JumpTable {
if libevmHooks == nil {
return jt
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm thinking, if a user calls overrideJumpTable, maybe we should panic if the libevmHooks is nil? It sounds a bit strange to pass in rules which just gets silently discarded by this function if the hooks are nil 🤔 We could handle the libevmHooks nil check at the calling layer instead?

s.overridden = true
for op, instr := range s.replacement {
if instr != nil {
fmt.Println(op, instr)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Remove print I think?

Suggested change
fmt.Println(op, instr)

Comment on lines +105 to +110
func TestOperationFieldCount(t *testing.T) {
// The libevm OperationBuilder assumes that the 6 struct fields are the only
// ones.
op := vm.OperationBuilder{}.Build()
require.Equalf(t, 6, reflect.TypeOf(*op).NumField(), "number of fields in %T struct", *op)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

This test is to make sure we update the Build method to set all fields in the future right?


_, gasRemaining, err := evm.Call(vm.AccountRef(rng.Address()), contract, []byte{}, gasLimit, uint256.NewInt(0))
require.NoError(t, err, "evm.Call([contract with overridden opcode])")
assert.Equal(t, gasLimit-gasCost, gasRemaining, "gas remaining")
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit I don't think there is a need to have an extra message, since assert.Equal would show the log line and it's relatively easy to understand what's going on without the gas remaining message I think

Suggested change
assert.Equal(t, gasLimit-gasCost, gasRemaining, "gas remaining")
assert.Equal(t, gasLimit-gasCost, gasRemaining)

_, gasRemaining, err := evm.Call(vm.AccountRef(rng.Address()), contract, []byte{}, gasLimit, uint256.NewInt(0))
require.NoError(t, err, "evm.Call([contract with overridden opcode])")
assert.Equal(t, gasLimit-gasCost, gasRemaining, "gas remaining")
assert.Equal(t, spy.stateVal, value, "StateDB propagated")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Shouldn't this be

Suggested change
assert.Equal(t, spy.stateVal, value, "StateDB propagated")
assert.Equal(t, spy.stateVal, value, "StateDB did not propagate")

opcode = 1
gasLimit uint64 = 1e6
)
rng := ethtest.NewPseudoRand(142857)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Any particular reason to use 142857? If not, maybe just use 0? 🤔

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