-
Notifications
You must be signed in to change notification settings - Fork 24
FLIP 255: Cadence WebAssembly API #256
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
Open
darkdrag00nv2
wants to merge
5
commits into
onflow:main
Choose a base branch
from
darkdrag00nv2:wasm
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
025d316
WIP FLIP for WebAssembly API Cadence
darkdrag00nv2 6f0eabb
Remove unnecessary function
darkdrag00nv2 fb47cda
Add a bit of detail about metering
darkdrag00nv2 aaf3b03
Apply suggestions from code review
turbolent 794ff28
improve proposal
turbolent File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,231 @@ | ||
| --- | ||
| status: proposed | ||
| flip: 255 | ||
| authors: darkdrag00n (darkdrag00n@proton.me), Bastian Müller (bastian.mueller@flowfoundation.org) | ||
| updated: 2024-11-13 | ||
| --- | ||
|
|
||
| # FLIP 255: Cadence WebAssembly API | ||
|
|
||
| ## Objective | ||
|
|
||
| This FLIP proposes the addition of an API to allow the execution of WebAssembly programs in Cadence. | ||
|
|
||
| ## Motivation | ||
|
|
||
| More and more projects are putting non-trivial computationally expensive logic in Cadence. | ||
| Examples of this are games or zero-knowledge proof checks. | ||
| Developers would also like to utilize code written in other programming languages. | ||
|
|
||
| Support for WebAssembly in Cadence could enable such workloads. | ||
| For example, same way Python developers often import numerical libraries written in C, | ||
| Cadence developers might also want to import such and other libraries into Cadence. | ||
|
|
||
| The motivation is explained in further details in | ||
| [this forum post](https://forum.flow.com/t/idea-wasm-execution-engine-in-cadence/5164) by Dieter Shirley. | ||
|
|
||
| ## User Benefit | ||
|
|
||
| Adding support for WebAssembly to Cadence has several benefits. | ||
|
|
||
| First, it allows developers to implement and speed up computationally expensive pure logic calculations, | ||
| which can be efficiently executed in WebAssembly. | ||
|
|
||
| Developers will also benefit from using existing non-Cadence programs, such as Rust or C, | ||
| by compiling such code to WebAssembly. | ||
|
|
||
| ## Proposal | ||
|
|
||
| ### Scope | ||
|
|
||
| This proposal targets a first, small iteration on adding a WebAssembly API to Cadence, | ||
| mostly focusing on allowing developers to utilize the algorithmic throughput provided by WebAssembly. | ||
|
|
||
| The scope of this proposal is as follows: | ||
|
|
||
| 1. Allow Cadence programs to instantiate a WebAssembly module. | ||
| 2. Allow Cadence programs to call functions exported from the WebAssembly module. | ||
|
|
||
| The WebAssembly module must: | ||
| - Not define any imports, i.e. the WebAssembly module has no access to Cadence, | ||
| and other imports such as memories, globals, and tables are not supported | ||
| - Only export functions, i.e. other exports such as memories, globals, and tables are not supports | ||
| - Use the functionality defined in the [WebAssembly Core Specification 1.0](https://www.w3.org/TR/wasm-core-1/). | ||
| Other extensions, such as the following, but not limited to, are not supported: | ||
| - Bulk memory | ||
| - Sign extension | ||
| - Multi value | ||
| - Multi memory | ||
| - 64-bit memor | ||
| - Mutable globals | ||
| - Reference types | ||
| - Tail calls | ||
| - Extended const | ||
| - Saturating float to int | ||
| - Atomics | ||
| - SIMD | ||
| - NaNs need to be canonicalized | ||
|
|
||
| Function exports must only have argument and return value types `i32` or `i64`. | ||
| Floats (`f32` or `f64`) are not supported. | ||
|
|
||
| ### Design | ||
|
|
||
| The WebAssembly API will be implemented as a Cadence contract and will expose functions and structs to use them. | ||
|
|
||
| The API is inspired by the [WebAssembly JavaScript Interface](https://www.w3.org/TR/wasm-js-api-2/#webassembly-namespace). | ||
|
|
||
| There are two main structs that will be exposed via the contract: | ||
|
|
||
| 1. `InstantiatedSource`: Represents a WebAssembly module and its instance. | ||
| The instantiated source only provides access to the instance. | ||
| The WebAssembly module cannot be introspected. | ||
|
|
||
| 2. `Instance`: Represents an instance of an instantiated WebAssembly module. | ||
| The instance only provides access to the exported functions. | ||
|
|
||
| The `InstantiatedSource` can be created using the `compileAndInstantiate` function. | ||
| It takes a WebAssembly module in binary format and compiles and instantiates it. | ||
|
|
||
| ```cadence | ||
| access(all) | ||
| contract WebAssembly { | ||
|
|
||
| /// Compile WebAssembly binary code into a Module | ||
| /// and instantiate it. Imports are not supported. | ||
| access(all) | ||
| view fun compileAndInstantiate(bytes: [UInt8]): &WebAssembly.InstantiatedSource | ||
|
|
||
| access(all) | ||
| struct InstantiatedSource { | ||
|
|
||
| /// The instance. | ||
| access(all) | ||
| let instance: &WebAssembly.Instance | ||
| } | ||
|
|
||
| struct Instance { | ||
|
|
||
| /// Get the exported value. | ||
| access(all) | ||
| view fun getExport<T: AnyStruct>(name: String): T | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| #### Example | ||
|
|
||
| Example usage of the WASM API to load a simple `add(i32, i32) -> i32` function, | ||
| calling it with Cadence `Int32` values, and getting back the result as a Cadence `Int32`: | ||
|
|
||
| ```cadence | ||
|
|
||
| access(all) | ||
| func main() { | ||
| // A simple program which exports a function `add` with type `(i32, i32) -> i32`, | ||
| // which sums the arguments and returns the result: | ||
| // | ||
| // (module | ||
| // (type (;0;) (func (param i32 i32) (result i32))) | ||
| // (func (;0;) (type 0) (param i32 i32) (result i32) | ||
| // local.get 0 | ||
| // local.get 1 | ||
| // i32.add) | ||
| // (export "add" (func 0))) | ||
| // | ||
| let addProgram: [UInt8] = [ | ||
| 0, 97, 115, 109, 1, 0, 0, 0, 1, 7, 1, 96, | ||
| 2, 127, 127, 1, 127, 3, 2, 1, 0, 7, 7, 1, | ||
| 3, 97, 100, 100, 0, 0, 10, 9, 1, 7, 0, 32, | ||
| 0, 32, 1, 106, 11, | ||
| ] | ||
|
|
||
| let instance = WebAssembly.compileAndInstantiate(bytes: program).instance | ||
| let addFn = instance.getExport<fun(Int32, Int32): Int32>(name: "add") | ||
|
|
||
| let sum1 = addFn(1, 2) // 3 | ||
| let sum2 = addFn(1, -100) // -99 | ||
| } | ||
| ``` | ||
|
|
||
| #### Implementation | ||
|
|
||
| An implementation of this proposal will likely use an existing WebAssembly execution environment | ||
| that satisfies the requirements. | ||
|
|
||
| #### Metering | ||
|
|
||
| Like regular Cadence programs, | ||
| code executed and the memory consumed by the WebAssembly execution environment must be limited and metered. | ||
|
|
||
| ##### Computation | ||
|
|
||
| The specifics of exactly how computation usage is limited and metered is an implementation detail. | ||
|
|
||
| Popular WebAssembly execution environments support some form to limit and meter the amount of executed code. | ||
| Such a mechanism is required and will be used to implement the computation metering. | ||
| The mechanism must be compatible and integrate with the metering of the FVM. | ||
|
|
||
| The high level idea of computation metering is: | ||
| 1. The FVM needs a mechanism to provide the number of remaining computation units to Cadence. | ||
| 2. Computation units are converted to the equivalent of the WebAssembly execution environment equivalent ("engine units"). | ||
| For example, the wasmtime engine has the concept of "fuel", and has a cost associated with each executed instruction. | ||
| 3. The WebAssembly code is executed with an upper limit of engine units determined from the available FVM computation units. | ||
| 4. If the execution exceeds the limit, execution is aborted and the Cadence program is aborted. | ||
| 5. If the execution succeeds, the amount of engine units is converted back to FVM computation units and metered. | ||
|
|
||
| ##### Memory | ||
|
|
||
| The specifics of exactly how memory usage is limited and metered is an implementation detail. | ||
|
|
||
| To limit the memory being consumed, some constraints will be defined | ||
| on the various ways that memory is used within the WebAssembly execution environment. | ||
|
|
||
| While the specifics are not defined in this proposal, | ||
| the following aspects will be limited and metered: | ||
| 1. Stack size/depth | ||
| 2. Linear memory (number of WebAssembly pages) | ||
| 3. Number and size of tables | ||
|
|
||
| ### Drawbacks | ||
|
|
||
| None | ||
|
|
||
turbolent marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ### Alternatives Considered | ||
|
|
||
| None | ||
|
|
||
| ### Performance Implications | ||
|
|
||
| None | ||
|
|
||
| ### Dependencies | ||
|
|
||
| None | ||
turbolent marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| ### Engineering Impact | ||
|
|
||
| It would require 3-4 weeks of engineering effort to implement, review & test the feature. | ||
|
|
||
| ### Compatibility | ||
|
|
||
| This change has no impact on compatibility between systems (e.g. SDKs). | ||
|
|
||
| ### User Impact | ||
|
|
||
| The proposed feature is a purely additive. | ||
| There is no impact on existing contracts and new transactions. | ||
|
|
||
| ## Related Issues | ||
|
|
||
| None | ||
|
|
||
| ## Questions and Discussion Topics | ||
|
|
||
| None | ||
|
|
||
| ## Implementation | ||
|
|
||
| Will be done as part of https://github.com/onflow/cadence/issues/2853. | ||
|
|
||
| A proof of concept has already been done as part of https://github.com/onflow/cadence/pull/2760. | ||
turbolent marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.