-
Notifications
You must be signed in to change notification settings - Fork 147
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
Atomic vm wrapper #758
Atomic vm wrapper #758
Conversation
plugin/evm/vm.go
Outdated
// VM implements the snowman.ChainVM interface | ||
type VM struct { | ||
// sharedEvm implements the snowman.ChainVM interface | ||
type sharedEvm struct { |
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.
Could we put this back? "VM" seems sufficient and as the wrapped VM is in another package it seems that we can leave this.
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 dont want to export this as without default extensions it will break. we can check if required extensions are nil in initialize to make sure it won't break if we want to. but I still slightly think we should not directly expose vm.
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.
Smaller API / less exported is always a good thing imo, so happy to keep this unexported. Now yeah it's more not-necessarily-necessary git diffs, but fine with me.
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 don't think sharedEvm
is a good name here (what is it shared between? runtime? compile time?) Perhaps we can use a more descriptive name or vm
?
I don't disagree that unexported is better, but renaming this seems like it should be its own PR as it is not necessary for this PR and makes this PR difficult to follow.
} | ||
|
||
// Initialize implements the snowman.ChainVM interface | ||
func (vm *VM) Initialize( |
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.
possibly instead of plugin/evm/atomic/vm
, we can have plugin/evm/coreth
which defines the VM for use in avalanchego.
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.
Yes, I think we probably would want to have a coreth/ and subnet-evm/ packages in the merged repo. For now I did not want to break the avalanchego.
plugin/evm/block.go
Outdated
atomicTxs []*atomic.Tx | ||
} | ||
|
||
// newBlock returns a new Block wrapping the ethBlock type and implementing the snowman.Block interface | ||
func (vm *VM) newBlock(ethBlock *types.Block) (*Block, error) { | ||
func (vm *sharedEvm) newBlock(ethBlock *types.Block) (*Block, error) { |
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 assume some further changes to block.go
is needed to fully have the atomic vm separated from the "base" evm that we can share with subnet-evm?
plugin/evm/admin.go
Outdated
profiler profiler.Profiler | ||
} | ||
|
||
func NewAdminService(vm *VM, performanceDir string) *Admin { | ||
func NewAdminService(vm *sharedEvm, performanceDir string) *Admin { |
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 should be an unexported function. Otherwise the vm
argument type should either be exported or be an exported interface (preferrable). But in this case, NewAdminService
is only used once in the same package, I'd just unexport it.
plugin/evm/factory.go
Outdated
type Factory struct{} | ||
|
||
func (*Factory) New(logging.Logger) (interface{}, error) { | ||
return &VM{}, nil | ||
return atomicvm.WrapVM(NewExtensibleEVM(false)), nil |
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.
supernit: you can use constants to indicate what the bool argument is, it's nice for readability instead of having to hover over the function to check what the argument is / check the fn in code when PR reviewing on the github website
return atomicvm.WrapVM(NewExtensibleEVM(false)), nil | |
const isPlugin = false | |
return atomicvm.WrapVM(NewExtensibleEVM(isPlugin)), nil |
Same for NewPlugin
below 😉
plugin/evm/vm.go
Outdated
// NewDefaultEVM returns a new instance of the VM with default extensions | ||
// This should not be called if the VM is being extended | ||
func NewDefaultEVM() *sharedEvm { |
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.
Since this is only used in tests, move it to a _test.go file? You could have a helpers_test.go
since it's used in various test files. Unless we want to use elsewhere 🤔
And then you can pass in a t *testing.T
and use require.NoError(t, err)
for error checks.
If this is meant to be used in production code, we really need to return an error I think? Even if it's mean to be in production code later, I'd rather have it in test code and then migrated to production code when it's used in production code at a later time.
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 moved it to test for now, alternatively we can check these extension points in Initialize
if they're nil, and if so we can provide some defaults in the vm.Initialize()
directly.
plugin/evm/vm.go
Outdated
return vm | ||
} | ||
|
||
func NewExtensibleEVM(isPlugin bool) *sharedEvm { |
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.
unexport this since it's only used in plugin/evm
If you want to export it for user by other packages, then export sharedEVM (aka re-use older VM
name and reduce diffs at the same time)
var networkCodec codec.Manager | ||
|
||
func init() { | ||
var err error | ||
networkCodec, err = message.NewCodec(message.BlockSyncSummary{}) | ||
if err != nil { | ||
panic(err) | ||
} | ||
} |
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.
Instead of having this at global scope with an init block, you could have the networkCodec created each time it's needed (in 5 places below in this same file) with
networkCodec, err := message.NewCodec(message.BlockSyncSummary{})
require.NoError(t, err)
It's always better to avoid global state / init blocks if possible.
plugin/evm/factory.go
Outdated
// TODO: either move this from plugin or move the VM itself | ||
type Factory struct{} |
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.
Why do we use a factory after all actually? It looks like it's only used in plugin/main.go as
rpcchainvm.Serve(context.Background(), factory.NewPlugin())
It makes no sense to have a factory as far as I understood 🤔 ?
which could well be replaced with
factory := evm.Factory{}
rpcchainvm.Serve(context.Background(), evm.NewPlugin())
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.
Normally We implement vms.Factory
from avalanchego
https://github.com/ava-labs/coreth/blob/master/plugin/evm/factory.go#L16
which is used here:
https://github.com/ava-labs/avalanchego/blob/add-l1-validators-api/node/node.go#L1240
but yea this can just be a function
Co-authored-by: Quentin McGaw <[email protected]> Signed-off-by: Ceyhun Onur <[email protected]>
Co-authored-by: Quentin McGaw <[email protected]> Signed-off-by: Ceyhun Onur <[email protected]>
Co-authored-by: Quentin McGaw <[email protected]> Signed-off-by: Ceyhun Onur <[email protected]>
Co-authored-by: Quentin McGaw <[email protected]> Signed-off-by: Ceyhun Onur <[email protected]>
plugin/evm/vm.go
Outdated
// VM implements the snowman.ChainVM interface | ||
type VM struct { | ||
// sharedEvm implements the snowman.ChainVM interface | ||
type sharedEvm struct { |
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 don't think sharedEvm
is a good name here (what is it shared between? runtime? compile time?) Perhaps we can use a more descriptive name or vm
?
I don't disagree that unexported is better, but renaming this seems like it should be its own PR as it is not necessary for this PR and makes this PR difficult to follow.
plugin/evm/vm.go
Outdated
@@ -314,14 +308,26 @@ type VM struct { | |||
rpcHandlers []interface{ Stop() } | |||
} | |||
|
|||
func newExtensibleEVM(isPlugin bool) *sharedEvm { |
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.
could we have a function like newVM that takes the codec.Manager
and drop the SetNetworkCodec function below?
It seems this type is not fully initialized even if it is constructed with a "new" function.
We can pass the "additional extension points" in to the "new" function (either as separate arguments or as a config struct), as all the customization should be known at construction time (i.e., is this VM coreth or subnet-evm).
Why this should be merged
This adds a way to extend the inner EVM and wraps it with atomic VM. For demonstration it sets the network codec with atomic codec.
How this works
This pull request introduces significant changes to the
plugin/evm
package to improve the extensibility and modularity of the EVM (Ethereum Virtual Machine) implementation. The primary focus is on creating a newVM
wrapper and updating initialization procedures to support network codec management. Here are the most important changes:Unexported Shared EVM
New VM Wrapper and Initialization
plugin/evm/atomic/vm/vm.go
: Introduced a newVM
wrapper that implements multiple interfaces (secp256k1fx.VM
,block.ChainVM
,block.BuildBlockWithContextChainVM
,block.StateSyncableVM
). Added theWrapVM
function to wrap anInnerVM
and theInitialize
method to set up the network codec.Factory Updates
plugin/evm/factory.go
: Modified theFactory
struct to return the newVM
wrapper in theNew
andNewPlugin
methods, allowing the EVM to be used as a plugin with the appropriate network codec setup. [1] [2]Codec Management
plugin/evm/vm.go
: Removed the globalnetworkCodec
variable and added anetworkCodec
field to theVM
struct. Implemented theSetNetworkCodec
method to manage the codec. Updated various methods to use thenetworkCodec
field instead of the global variable. [1] [2] [3] [4] [5] [6] [7] [8]Test Updates
plugin/evm/vm_warp_test.go
: Added initialization of thenetworkCodec
variable in tests to ensure proper codec setup during test execution. [1] [2]Main Function Update
plugin/main.go
: Updated themain
function to use the newFactory
struct for creating the EVM plugin, ensuring the proper setup of the network codec.How this was tested
Existing UTs should cover, but might be refactored.
Need to be documented?
No
Need to update RELEASES.md?
No