-
Notifications
You must be signed in to change notification settings - Fork 2
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
base: main
Are you sure you want to change the base?
Conversation
|
||
package vm | ||
|
||
// An OperationBuilder is a factory for a new operations to include in a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// 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 |
func LookupInstructionSet(rules params.Rules) (jt JumpTable, err error) { | ||
defer func() { | ||
if err == nil { // NOTE `err ==` NOT != | ||
jt = *overrideJumpTable(rules, &jt) | ||
} | ||
}() |
There was a problem hiding this comment.
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 😉 !
func overrideJumpTable(r params.Rules, jt *JumpTable) *JumpTable { | ||
if libevmHooks == nil { | ||
return jt | ||
} |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove print I think?
fmt.Println(op, instr) |
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) | ||
} |
There was a problem hiding this comment.
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") |
There was a problem hiding this comment.
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
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") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be
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) |
There was a problem hiding this comment.
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
? 🤔
Why this should be merged
Allows for creation of unexported
vm.operation
s and their injection intovm.JumpTable
s through a registered hook.First step to full support of #22.
How this works
Introduces
vm.Hooks
that can be registered viavm.RegisterHooks()
. These are far simpler thanparams
hooks as they don't need payloads. Thevm.Hooks.OverrideJumpTable()
hook is used in bothNewEVMInterpreter()
andLookupInstructionSet()
to modify their respectiveJumpTable
s after creation. This couldn't be defined onparams.RulesHooks
due to a circular dependency.The
vm.OperationBuilder
factory is also introduced to allow creation of the otherwise unexportedoperation
type. I chose this pattern over a function because it makes arguments clearer at the usage site. To provide access to internal identifiers, the customOperationFunc
is an extension of the regularexecutionFunc
to also accept anOperationEnvironment
(similar to aPrecompileEnvironment
).How this was tested
Integration tests that demonstrate (a) honouring of the params hook signal; and (b) proper execution of a newly created
*operation
.