-
Notifications
You must be signed in to change notification settings - Fork 20.4k
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
EVMC support #17050
EVMC support #17050
Conversation
cc @gballet (I don't have the rights to make you the reviewer). |
core/vm/evmc.go
Outdated
defer C.free(unsafe.Pointer((centrypoint))) | ||
|
||
C.dlerror() | ||
createSymbol = C.dlsym(handle, centrypoint) |
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.
Cannot this iterate symbols here and find the first starting with evmc_create_
?
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.
The dl
library does not have any way to iterate over symbols. We'd have to use ELF library on Linux and something equivalent for MACHO on macOS. Possible in the future, but definitely overkill at the moment.
ethstats/ethstats.go
Outdated
@@ -380,11 +380,12 @@ func (s *Service) login(conn *websocket.Conn) error { | |||
network = fmt.Sprintf("%d", infos.Protocols["les"].(*les.NodeInfo).Network) | |||
protocol = fmt.Sprintf("les/%d", les.ClientProtocolVersions[0]) | |||
} | |||
node := strings.Replace(infos.Name, "Geth", "Geth+EVMC", 1) |
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.
Please don't modify the reported name here. If yu need a different name, update it where the name is created to include any additional info you'd like.
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 could not find where the name comes from, but this is not going to stay.
Don’t seem to have a submodule, does this rely on having |
To compile: changed the include path in |
One issue I find with this that the existence of the requested VM is not checked on startup, e.g. |
I will pull your change to make it easier for now. The final solution would be to include evmc Go wrapper in ethereum/evmc repo and use that as a Go package here. No git submodule would be needed then.
Yes. Command line arguments in geth are quite flaky and to pass the path to VM you would have to change ~20 places (not all of them are covered at the moment, I added some workarounds). That requires discussion with Go team. |
50a58f3
to
c425949
Compare
Big update! See the top comment. |
Needs rebase after #17093 was merged. |
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.
Please update the code to implement the Interpreter
interface, as it has been added especially to support this use case.
.gitmodules
Outdated
@@ -1,3 +1,6 @@ | |||
[submodule "tests"] | |||
path = tests/testdata | |||
url = https://github.com/ethereum/tests | |||
[submodule "evmc"] |
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 creates a strong dependency on an optional component. Since you have the EVMCPathFlag
parameter, you can use it to download. Most clients will not use the evmc at this stage, so forcing them to download the code for it is overkill.
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.
EVMC is only the C header plus the Go binding for it, doesn't include any VM implementation. I think it is needed, due it being a compile time dependency?
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.
My bad, the previous comment was very poorly worded: you should use go's own opinionated package system and add the dependency to vendor/vendor.json
with the govendor
utility.
core/vm/evm.go
Outdated
@@ -122,7 +122,7 @@ func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmCon | |||
chainRules: chainConfig.Rules(ctx.BlockNumber), | |||
} | |||
|
|||
evm.interpreter = NewInterpreter(evm, vmConfig) | |||
evm.interpreter = NewEVMC(evm, vmConfig) |
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.
We should make it depend on a switch, like:
if vmConfig.EVMCPath != "" {
evm.interpreter = NewEVMC(evm, vmConfig)
} else {
evm.interpreter = newInterpreter(evm, vmConfig)
}
cmd/utils/flags.go
Outdated
@@ -355,6 +355,11 @@ var ( | |||
Name: "vmdebug", | |||
Usage: "Record information useful for VM and contract debugging", | |||
} | |||
EVMCPathFlag = cli.StringFlag{ | |||
Name: "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.
This should then be --evmc
or --evmc-vm
, there are other, non-EVMC compliant VMs.
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.
We can make it nicer by allowing options like:
--vm auto
--vm interpreter
--vm ewasm
--vm /path/to/evmc.so
This flag does not work anyway, so I'm removing it for now.
core/vm/evm.go
Outdated
@@ -139,7 +139,7 @@ func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmCon | |||
interpreters: make([]Interpreter, 1), | |||
} | |||
|
|||
evm.interpreters[0] = NewEVMInterpreter(evm, vmConfig) | |||
evm.interpreters[0] = NewEVMC(evm, vmConfig) |
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 the merge of #17093, you can support other interpreters; this disables the evm interpreter which is not acceptable. What should happen is that if --evmc-vm
is passed as an argument, then an EVMC interpreter should be inserted before. Something like:
if cfg.EVMCPath != nil {
old := evm.interpreters
evm.interpreters = make([]Interpreter, len(evm.interpreters)+1)
evm.interpreters[0] = NewEVMC(evm, vmConfig)
copy(evm.interpreters[1:], old)
}
core/vm/evmc.go
Outdated
return evmcInstance | ||
} | ||
|
||
func NewEVMC(env *EVM, cfg Config) *EVMC { |
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.
EVMC
should implement the Interpreter
interface, see https://github.com/ethereum/go-ethereum/blob/master/core/vm/interpreter.go#L48
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.
It does.
output, gasLeftU, err = env.Call(host.contract, destination, input, gasU, value) | ||
} | ||
case evmc.DelegateCall: | ||
output, gasLeftU, err = env.DelegateCall(host.contract, destination, input, gasU) |
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.
Should any of these panic if static
is set or is it handled up in the interface?
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.
static
is magically handled inside, but this seems to be bad design. Probably should be changed later on to be handled internally in any VM.
f8a704d
to
f1882d1
Compare
@gballet I believe I addressed all your comments. |
#17461 could simplify this a bit. |
core/vm/evmc.go
Outdated
|
||
func getRevision(env *EVM) evmc.Revision { | ||
n := env.BlockNumber | ||
if env.ChainConfig().IsByzantium(n) { |
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.
Is there a constantinople setting now in master
, which needs to be supported here?
Please update to EVMC 5.2.0. @chfast should support for |
} | ||
|
||
func (evm *EVMC) CanRun([]byte) bool { | ||
return true |
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.
There are two issues here:
- The EVMC will always try to execute the contract. There could be another interpreter that supports a format that the EVMC doesn't, and the native Go interpreter should be the default one in any case.
- In the case of a mixed network that supports EVM+EWASM contracts, you need to have an external switch to be able to execute hera in mode
evm1mode=fallback
as discussed here, because right now it will always try to execute everything as WASM and that behavior is controlled by something outside of geth, which is horrible usability-wise.
So determining the proper format should be more advanced in any case.
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.
So it should be false
and then never run? EVMC is not for ewasm only, I'm using it with C++ EVM interpreter. I believe if an user specifies the execution as geth --vm myvm.so
he really wants to use myvm.so
.
You should rethink this CanRun()
feature.
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.
the feature has been thought through enough, thank you. If you have geth --vm myvm.so
you are stuck with only one interpreter, whereas this supports a mixed chain with different formats.
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 will be handled with EVMC 6.
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.
then in EVMC-6, and provided the right command line switch, the return value here should be true. Until then, it should check if the format is wasm and, if not, return false.
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 would break geth + aleth-interpreter.
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.
Please be more specific. How would that break geth + aleth ?
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 need geth + aleth-interpreter for testing. Aleth is EVM and if we check for wasm bytecode here it will be skip and the execution fallback to Go Interpreter.
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.
Anyway, I'm not aiming to merge this PR now. We should definitely wait for EVMC 6 which should be soon.
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.
ok let's do that. In the mean time, here is the PR that implements all the command line switches: #17687
core/vm/evm.go
Outdated
@@ -139,7 +140,11 @@ func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmCon | |||
interpreters: make([]Interpreter, 1), | |||
} | |||
|
|||
evm.interpreters[0] = NewEVMInterpreter(evm, vmConfig) | |||
if len(os.Getenv("EVMC_PATH")) != 0 { |
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.
Let's use a command line switch instead, env variables are transient and they lead to multi-steps instructions; it's better to have all non-privacy-sensitive configuration in one place.
furthermore, this de-activates the EVM and that's a no go: the EVM needs to remain as a backup. I suggest:
if vmConfig.evmcPath != 0 {
evm.interpreters = append(evm.interpreters, NewEVMC(evm))
}
evm.interpreters = append(evm.interpreters, NewEVMInterpreter(evm, vmConfig))
Then line 140 should be replaced with
interpreters: []Interpreter{}
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.
What exactly is geth doing with that list?
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 tried the command line switch but this is not doable currently (at least not in this PR) because the VMConfig{}
is created in 100 places usually with default value just because the it is required to create an EVM.
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.
@axic it lists the interpreters, so as to be able to find the best format for a given executable. This is how you can mix EVM&EWASM contracts.
Done.
Let's wait for capabilities from EVMC 6. |
Please rebase over #17687 (well, master) so that we can support fallback to EVM. |
core/vm/evmc.go
Outdated
defer func() { evm.readOnly = false }() | ||
} | ||
|
||
fmt.Printf("depth: %d kind: %d static: %t\n", evm.env.depth, kind, readOnly) |
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.
Debug to be removed?
govendor fetch github.com/ethereum/evmc/bindings/go/evmc@=v5.2.0
Replaced with #17954 |
Usage:
EVMC_PATH
env var.EVMC_OPTIONS
env var, e.g.EVMC_OPTIONS='debug=on evm2wasm=true'
.