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

new feature flag: deterministic #709

Merged
merged 10 commits into from
Dec 6, 2019
Merged

Conversation

YaronWittenstein
Copy link
Contributor

@YaronWittenstein YaronWittenstein commented Aug 22, 2019

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.

@YaronWittenstein YaronWittenstein changed the title Deterministic new feature flag: deterministic Aug 22, 2019
@ethanfrey
Copy link
Contributor

Interesting idea. I am also looking for deterministic execution in for a blockchain project.
I had assumed that simply disabling floating point in the wasm will get you deterministic execution (CosmWasm/cosmos-sdk#6)

I'd be happy for you to explain to me what other sources you found, and how this disables them

@MarkMcCaskey
Copy link
Contributor

@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)

@YaronWittenstein
Copy link
Contributor Author

YaronWittenstein commented Oct 6, 2019

@ethanfrey Hi!

You're right. The main motivation is right now disabling floats.
But in the future, it might be more features (as @MarkMcCaskey said)

I'll update the PR soon since the code isn't synced with master

@ethanfrey
Copy link
Contributor

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.
Copy link
Contributor

@MarkMcCaskey MarkMcCaskey left a 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.

@@ -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"]
Copy link
Contributor

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

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 }
Copy link
Contributor

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

Copy link
Contributor Author

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

Copy link
Contributor

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...

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

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!

Copy link
Contributor Author

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...

Copy link
Contributor

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.

Copy link
Contributor Author

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?

Copy link
Contributor

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.

Copy link
Contributor

@Hywan Hywan left a 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"]

Copy link
Contributor

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.

Copy link
Contributor Author

@YaronWittenstein YaronWittenstein Oct 7, 2019

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)

Copy link
Contributor Author

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

Copy link
Contributor Author

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

Copy link
Contributor Author

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

@ethanfrey
Copy link
Contributor

This also seems to just be for single pass.
Is there a way to return an error on detecting floating point (disable it) for other compilers?

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?

@YaronWittenstein
Copy link
Contributor Author

This also seems to just be for single pass.
Is there a way to return an error on detecting floating point (disable it) for other compilers?

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

@MarkMcCaskey
Copy link
Contributor

@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.

@ethanfrey
Copy link
Contributor

@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

@ethanfrey
Copy link
Contributor

ethanfrey commented Oct 11, 2019

@YaronWittenstein

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:

Backend Gas Metering Serialization Compile Speed Run Speed Toolchain
Singlepass Yes No Fast Slow Nightly
Cranelift No Yes Medium Medium Stable
LLVM Yes Yes Slow Fast Stable

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.

@YaronWittenstein
Copy link
Contributor Author

@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

@ethanfrey The determinstic feature has been implemented here:
yurydelendik/wasmparser.rs@dd0a114

I guess can have deterministic for more backends. maybe we can have backend type feature
orthogonal to the deterministic feature.

@YaronWittenstein
Copy link
Contributor Author

What's the status here? It seems like a very nice feature for the blockchain use-case, but I don't see any movement here.

I am sticking with singlepass for my integration now as well. Especially since llvm support is even harder than I thought (it cannot be published to crates.io due to dependencies inkwell that are structured in a way to prevent that). And I don't see much movement on metering coming to cranelift.

I agree. I'm just not sure what I should do next here... like do we need to support more compilers?

@MarkMcCaskey
Copy link
Contributor

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

@AdamSLevy
Copy link

AdamSLevy commented Dec 3, 2019

Is there a way to return an error on detecting floating point (disable it) for other compilers?

@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
Copy link
Contributor Author

Is there a way to return an error on detecting floating point (disable it) for other compilers?

@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.

https://github.com/spacemeshos/svm/blob/develop/crates/svm-compiler/src/middleware/validation.rs#L154

@ethanfrey
Copy link
Contributor

@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

@YaronWittenstein
Copy link
Contributor Author

@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
How about that I'll open a PR with the code of the middleware rejecting instructions related to floats / other non-deterministic related features?

Ideally, I'd like to have wasmer expose a feature-flag for deterministic execution.
However, some clients might choose to execute different inputs with different middlewares-chains
(so such middleware can help with that).

@MarkMcCaskey
Copy link
Contributor

@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!

@MarkMcCaskey
Copy link
Contributor

bors r+

@bors
Copy link
Contributor

bors bot commented Dec 5, 2019

👎 Rejected by too few approved reviews

@MarkMcCaskey
Copy link
Contributor

bors r+

bors bot added a commit that referenced this pull request Dec 5, 2019
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 <yaron.wittenstein@gmail.com>
Co-authored-by: Yaron Wittenstein <yaronwittenstein@users.noreply.github.com>
Co-authored-by: Mark McCaskey <5770194+markmccaskey@users.noreply.github.com>
@bors
Copy link
Contributor

bors bot commented Dec 5, 2019

Build failed

@MarkMcCaskey
Copy link
Contributor

Okay, so I ran into some issues with this that need to be resolved:

I think the deterministic-execution flag needs to be completely orthogonal to the default-backendflags. It makes the conditional logic really complicated and if someone wants to use determinism than they should be using a backend explicitly, not relying on the the automatic backend logic (which could break due to being extremely complex and then break their system). We'll need to document how to go about using this properly somewhere though and talk about the strengths and weaknesses of our backends so that users can make an informed choice.

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

@MarkMcCaskey
Copy link
Contributor

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

@MarkMcCaskey
Copy link
Contributor

@YaronWittenstein ping me when you have a chance to review and merge the PR ^ ! Then I'll ship this one

@MarkMcCaskey
Copy link
Contributor

bors r+

bors bot added a commit that referenced this pull request Dec 6, 2019
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 <yaron.wittenstein@gmail.com>
Co-authored-by: Yaron Wittenstein <yaronwittenstein@users.noreply.github.com>
Co-authored-by: Mark McCaskey <5770194+markmccaskey@users.noreply.github.com>
Co-authored-by: Mark McCaskey <mark@wasmer.io>
Co-authored-by: Nick Lewycky <nick@wasmer.io>
@bors
Copy link
Contributor

bors bot commented Dec 6, 2019

Build failed (retrying...)

bors bot added a commit that referenced this pull request Dec 6, 2019
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 <yaron.wittenstein@gmail.com>
Co-authored-by: Yaron Wittenstein <yaronwittenstein@users.noreply.github.com>
Co-authored-by: Mark McCaskey <5770194+markmccaskey@users.noreply.github.com>
Co-authored-by: Mark McCaskey <mark@wasmer.io>
@bors
Copy link
Contributor

bors bot commented Dec 6, 2019

Build succeeded

@bors bors bot merged commit 6da3b22 into wasmerio:master Dec 6, 2019
@ethanfrey
Copy link
Contributor

Awesome! I can start using this with the next release

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.

5 participants