-
Notifications
You must be signed in to change notification settings - Fork 824
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
new feature flag: deterministic
#709
Conversation
Interesting idea. I am also looking for deterministic execution in for a blockchain project. I'd be happy for you to explain to me what other sources you found, and how this disables them |
@ethanfrey in the future, threads, too. I think we'd want to use this flag to be extra strict during the Wasm evaluation step (I don't have context on this PR, just commenting generally) |
@ethanfrey Hi! You're right. The main motivation is right now disabling floats. I'll update the PR soon since the code isn't synced with |
Great, I thought this was possible already, but if not, definitely an essential feature. |
…it'll guarantee deterministic execution of wasm programs across different hardware/circumstances. This is very useful for Blockchain projects having wasm smart-contracts This is critical for Blockchain projects that require execution to be deterministic in order to reach a consensus of the state transition of each smart-contract transaction.
46c2e82
to
6ca5812
Compare
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 test this flag with cargo check --features "deterministic"
in CI at the very least. It'd also be nice to have test cases of Wasm that fails when it's enabled and an example of Wasm that works. We can add the tests as a follow-up PR (except for the check) if you want to get this shipped quickly though.
lib/runtime/Cargo.toml
Outdated
@@ -41,6 +41,7 @@ singlepass = ["wasmer-singlepass-backend"] | |||
default-backend-singlepass = ["singlepass"] | |||
default-backend-llvm = ["llvm"] | |||
default-backend-cranelift = ["cranelift"] | |||
deterministic = ["wasmer-singlepass-backend/deterministic"] |
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 probably trigger wasmer-runtime-core/deterministic
, too
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 thought it's redundant because:
https://github.com/wasmerio/wasmer/blob/master/lib/singlepass-backend/Cargo.toml#L12
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's redundant in that all interactions with wasmer-runtime-core through singlepass will be deterministic as defined by that flag, but I believe Rust will compile a separate version of the crate with the other feature flags that are directly accessible from wasmer-runtime
Cargo.toml
Outdated
@@ -26,7 +26,7 @@ wabt = "0.9.1" | |||
wasmer-clif-backend = { path = "lib/clif-backend" } | |||
wasmer-singlepass-backend = { path = "lib/singlepass-backend", optional = true } | |||
wasmer-middleware-common = { path = "lib/middleware-common" } | |||
wasmer-runtime = { path = "lib/runtime" } | |||
wasmer-runtime = { path = "lib/runtime", default-features = 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.
Hmm, I don't know if we want to change 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.
otherwise, you force the installation of cranelift and it seems to break to compilation
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.
Yeah, you can only enable one default backend.
And you cannot disable default features from the deterministic
feature.
I dealt with this for my metering pr #736 and ended up just documenting that you had to explicitly set the backend with metering on...
cargo test --features metering,backend-singlepass --no-default-features
it is a bit heavier to use it, but still configurable and doesn't break anyone else's compile steps. Then again, this is trying to disable default features of a dependency... hmm...
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 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.
very nice @ethanfrey, thank you!
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.
@ethanfrey
I've reverted that and tried:
cargo +nightly build --features=deterministic --no-default-features
and for some reason, it installs cranelift...
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.
Yeah, what I was thinking was that if a user wanted to do this, then they could pass default-features = false
in their Cargo.toml of 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.
@MarkMcCaskey it means that a user will have to use a forked version then?
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.
A forked version of what exactly?
It's my understanding that this is a fully configurable way to do this. In Rust this is done in cargo.toml. In other things like the go-ext-wasm example, it uses an empty wrapper crate to pass configuration options into the Rust for the dynamic library that it creates.
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 rename the feature deterministic-execution
please? I feel like the subject is missing. We should also add a comment in the lowest-denominator Cargo.toml
file to explain what this feature is about. Thoughts?
Cargo.toml
Outdated
@@ -101,6 +101,8 @@ backend-singlepass = [ | |||
wasi = ["wasmer-wasi"] | |||
managed = ["backend-singlepass", "wasmer-runtime-core/managed"] | |||
|
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 the empty line between the features please.
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.
@Hywan I wanted to stay with the feature flag name of wasmparser
(also a shorter name)
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.
but it's your call of course
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.
@MarkMcCaskey @Hywan
please LMK what's your decision
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.
@MarkMcCaskey @Hywan
I've renamed the feature flag to deterministic-execution
4ba0bdd
to
7ce5ec4
Compare
This also seems to just be for single pass. Failing that maybe some other code that can parse wasm and detect if there are any floating point ops, as a pre processor? Hmmm... I guess this coild be a Middleware, right? |
I thought that smart contracts will use only the single-pass complier |
@ethanfrey I believe the feature passed to wasmparser does this, though I have not verified this. It's probably good for this feature to apply to all backends. @YaronWittenstein is correct that most users in blockchain or smart contract settings want to avoid super-linear compilation time on malicious input ("JIT-bombs"). That said, it would be nice to avoid fragmentation on the backends and I can imagine that this flag might be more generally useful. |
@MarkMcCaskey wasmparser is a nice link. Also nice as a quick pre-compile filter to ensure the proper imports and exports sections, etc. And quickly reject data that we don't even want to compile. I couldn't figure out how to quickly check for floating ops, but it does seem there are some hooks I could use, such as https://docs.rs/wasmparser/0.39.2/wasmparser/struct.CodeSectionReader.html |
That is a good point with single-pass to avoid attack vectors. Not sure what the routes are, I just figured you could use a heavier backend and raise the gas cost for creating a contract very high (per byte) and lower the cost for running them. My current design is actually only a few well designed contracts uploaded (can be expensive) and then instantiated many times (making a new erc20 token reuses the same code, just different initial config). But that is just my design, not a general rule. Also, the support matrix seems to be:
I want gas metering and serialization, and would prefer the stable toolchain. Which locks me to llvm now. I would consider singlepass (even with nightly) if it had serialization support - which means only compile once on upload, not on every run. And would gladly jump to cranelift when it supports gas metering #819 I say this to explain my thinking now. I am not sure it is the proper choice, and am very interested in feedback. |
@ethanfrey The I guess can have |
I agree. I'm just not sure what I should do next here... like do we need to support more compilers? |
I agree, I'm not sure what happened with this PR -- this is a feature we want to ship. I'll follow up with the team |
@ethanfrey it should be trivial to implement a middleware chain that can throw an error if any floating point Operators are detected. This would then be totally agnostic to the backend. |
|
@YaronWittenstein awesome link, great to see you have implemented the function as middleware. If I want to add this to my app, what is the suggested approach? I can just copy that file into my repo (it is MIT), but if this will hit upstream wasmer, I would import there. Or maybe I just import your svm-compiler crate (which is basically what I do in my singlepass compiler backend logic), but I don't think you are making stability guarantees there yet. Anyway, I'd love to integrate this code, let me know what you would suggest/prefer. Personally, I think this would be a great addition to wasmer-runtime |
@syrusakbary @MarkMcCaskey @Hywan Ideally, I'd like to have |
@YaronWittenstein yeah, that middleware sounds like it'd be good to have -- thanks! I'm actually going to merge master into this PR and then ship it and we can iterate on it after it's shipped. Sorry about dropping the ball on this one for so long! |
bors r+ |
👎 Rejected by too few approved reviews |
bors r+ |
709: new feature flag: `deterministic` r=MarkMcCaskey a=YaronWittenstein The motivation for the PR is for introducing a new feature flag called `deterministic`. When `deterministic` will be enabled (turned-off by default) it'll guarantee deterministic execution of wasm programs across different hardware/circumstances. This is critical for Blockchain projects that require execution to be deterministic in order to reach a consensus of the state transition of each smart-contract transaction. Co-authored-by: Yaron Wittenstein <[email protected]> Co-authored-by: Yaron Wittenstein <[email protected]> Co-authored-by: Mark McCaskey <[email protected]>
Build failed |
Okay, so I ran into some issues with this that need to be resolved: I think the We'll have to update the cfg flag checking tests too (should be easier now that there's less interaction) and ideally have other tests for something this important, but we can avoid most of that in this PR |
Okay! I've made a PR spacemeshos#1 ! when that gets merged, we can merge here. Once it's merged we can follow up on some of the specifics if you want to change them |
@YaronWittenstein ping me when you have a chance to review and merge the PR ^ ! Then I'll ship this one |
Deterministic
bors r+ |
709: new feature flag: `deterministic` r=MarkMcCaskey a=YaronWittenstein The motivation for the PR is for introducing a new feature flag called `deterministic`. When `deterministic` will be enabled (turned-off by default) it'll guarantee deterministic execution of wasm programs across different hardware/circumstances. This is critical for Blockchain projects that require execution to be deterministic in order to reach a consensus of the state transition of each smart-contract transaction. 865: adding tests for `state_creator` of `import_object` r=MarkMcCaskey a=YaronWittenstein Part of the PR #807 changes was adding support for shared import objects between threads. https://github.com/wasmerio/wasmer/pull/807/files#diff-d20cb4c5a883566b85be4cc046f45aa9R49 I've added tests/examples on how to create an `import object` with a state_creator (function or closure) 1042: Make regression test work in release builds too. r=nlewycky a=nlewycky Fix this regression test to detect the bug it was looking for in release builds too. This bug triggered an assertion failure in debug, and by examining the pre-opt IR, we can check for the bug in release mode too. Co-authored-by: Yaron Wittenstein <[email protected]> Co-authored-by: Yaron Wittenstein <[email protected]> Co-authored-by: Mark McCaskey <[email protected]> Co-authored-by: Mark McCaskey <[email protected]> Co-authored-by: Nick Lewycky <[email protected]>
Build failed (retrying...) |
709: new feature flag: `deterministic` r=MarkMcCaskey a=YaronWittenstein The motivation for the PR is for introducing a new feature flag called `deterministic`. When `deterministic` will be enabled (turned-off by default) it'll guarantee deterministic execution of wasm programs across different hardware/circumstances. This is critical for Blockchain projects that require execution to be deterministic in order to reach a consensus of the state transition of each smart-contract transaction. Co-authored-by: Yaron Wittenstein <[email protected]> Co-authored-by: Yaron Wittenstein <[email protected]> Co-authored-by: Mark McCaskey <[email protected]> Co-authored-by: Mark McCaskey <[email protected]>
Build succeeded |
Awesome! I can start using this with the next release |
The motivation for the PR is for introducing a new feature flag called
deterministic
.When
deterministic
will be enabled (turned-off by default) it'll guarantee deterministicexecution of wasm programs across different hardware/circumstances.
This is critical for Blockchain projects that require execution to be deterministic
in order to reach a consensus of the state transition of each smart-contract transaction.