-
Notifications
You must be signed in to change notification settings - Fork 0
feat: draft wrap 0.2 specification #5
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
Draft
Niraj-Kamdar
wants to merge
3
commits into
wrap-0.2-dev
Choose a base branch
from
wrap-0-2-spec
base: wrap-0.2-dev
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.
Draft
Changes from all commits
Commits
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,59 @@ | ||
| # WRAP 0.2 Motivation | ||
| The current WRAP standard (0.1) has lots of unnecessary imports that are making the standard bulky, increasing the potential attack vectors and breaking changes that can be avoided by refactoring the standard to remove most of these imports and moving the responsibilites of the current imports to the higher layer abstractions (e.g. plugins, client, etc). | ||
|
|
||
| Here is the list of all the imports and exports that this standard will be replacing: | ||
|
|
||
| 1) `_wrap_invoke` family of imports and exports: | ||
| a. `_wrap_invoke` | ||
| b. `__wrap_invoke_args` | ||
| c. `__wrap_invoke_result` | ||
| d. `__wrap_invoke_error` | ||
|
|
||
| 2) `__wrap_subinvoke` family of imports and exports: | ||
| a. `__wrap_subinvoke` | ||
| b. `__wrap_subinvoke_result_len` | ||
| c. `__wrap_subinvoke_result` | ||
| d. `__wrap_subinvoke_error_len` | ||
| e. `__wrap_subinvoke_error` | ||
|
|
||
| This standard will replace imports and exports necessary for invocation and subinvocation with following list of imports and exports: | ||
|
|
||
| - The `_invoke` export function can be used by the Host to call functions defined in the Wasm module. | ||
| - The `__subinvoke` import function can be used by the Wasm to call functions defined in the Host. | ||
| - The `__fill_buffer` import is a helper function that copies a prepared buffer, of the data host needs to send to the Wasm module, to the provided pointer in shared memory. | ||
|
|
||
| Here is the list of all the imports and exports that this standard will be removing: | ||
|
|
||
| 1) `__wrap_subinvokeImplementation` family of imports: | ||
| a. `__wrap_subinvokeImplementation` | ||
| b. `__wrap_subinvokeImplementation_result_len` | ||
| c. `__wrap_subinvokeImplementation_result` | ||
| d. `__wrap_subinvokeImplementation_error_len` | ||
| e. `__wrap_subinvokeImplementation_error` | ||
| 2) `__wrap_getImplementations` family of imports: | ||
| a. `__wrap_getImplementations` | ||
| b. `__wrap_getImplementations_result_len` | ||
| c. `__wrap_getImplementations_result` | ||
| 3) `__wrap_debug_log` import | ||
| 4) `__wrap_load_env` import | ||
| 5) `__wrap_abort` import | ||
|
|
||
| Before jumping into why are we removing this and how it will be replaced, let's talk about what is the purpose of these imports in the current standard | ||
|
|
||
| 1) `__wrap_subinvokeImplementation` and `__wrap_getImplementations`: | ||
|
|
||
| These 2 imports are related to the interface-implementations functionality we provide via the client. | ||
|
|
||
| Currently, a WRAP developer can create any interface and other developers can implement this interface. This allows creating extensible software like the defiwrapper. To achieve this, the client provides a config to register the list of interfaces and its implementations. | ||
|
|
||
| We allow executing these implementations inside the wrapper in 2 different ways: 1) wrapper can get implementations registered with the client for the given interface and execute any/all of these implementations. 2) wrapper can dynamically execute any implementation wrapper if it knows its URI. | ||
|
|
||
| `__wrap_subinvokeImplementation` import works similarly to the `__wrap_subinvoke` but instead of just taking the URI of the wrapper we want to subinvoke, it will also take the URI of interface wrapper. The interface uri isn't being used for anything currently and this import works in exactly the same way as the `__wrap_subinvoke` works. The idea behind this import was to evantually support only allowing the valid interface-implementations to be executed but currently it doesn't serve any purpose. | ||
|
|
||
| `__wrap_getImplementations` allows us to get implementations of an interface that is registered using client. Responsibility of this function can be moved to higher layers of abstraction. | ||
|
|
||
| `__wrap_debug_log` is a dev experience import that we introduced to log the message to console while developing the wrapper but it's a potential security issue and breaks the sandboxed guarantees of the runtime. | ||
|
|
||
| `wrap_load_env` is used for loading environment variables set by client to the wasm wrapper. Responsibility of this function can be moved to higher layers of abstraction. | ||
|
|
||
| `wrap_abort` is used for aborting execution of Wasm module when there is any exception. Responsibility of this function can be moved to higher layers of abstraction. |
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,132 @@ | ||
| # WRAP Specification | ||
|
|
||
| WRAP defines a set of standards for creating extensible packages that can run on any platform. | ||
| The core principles of WRAP are: | ||
| - Portability | ||
| - Extensibility | ||
| - Composability | ||
| - Security | ||
|
|
||
| ## WRAP package | ||
| WRAP package is a collection that contains a WRAP manifest, a Wasm module and optional resource files. | ||
|
|
||
| ### WRAP manifest | ||
| The WRAP manifest is a MessagePack encoded binary file that contains metadata about a WRAP package. | ||
| The metadata consists of the following: | ||
| - Version of the WRAP specification | ||
| - Name of the WRAP package | ||
| - Application Binary Interface (ABI) | ||
|
|
||
| ### WRAP module | ||
| The WRAP module is a Wasm module that allows for bi-directional communication between the Host and itself by defining the processes of invocation and subinvocation. | ||
|
|
||
| It makes use of Host allocated shared memory to pass encoded buffers between the Host and the Wasm module. | ||
|
|
||
| The Wasm module must define the following imports and exports: | ||
|
|
||
| #### Exports | ||
| - `_invoke: (optBufLen: u32) => u32` | ||
| - Used for invoking functions defined in the Wasm module. | ||
| - *Params:* | ||
| - `optBufLen(u32)` is the length of the encoded invocation options buffer | ||
| - *Returns(u32):* the 8 byte long response buffer which contains length of the result buffer + pointer to the result buffer | ||
|
|
||
| #### Imports | ||
| - `__subinvoke: (optBufPtr: u32, optBufLen: u32) => u32` | ||
| - Used for subinvoking functions defined in the Host. | ||
| - *Params:* | ||
| - `optBufPtr(u32)` is the pointer to the encoded subinvocation options buffer | ||
| - `optBufLen(u32)` is the length of the encoded subinvocation options buffer | ||
| - *Returns(u32):* the length of the subinvocation result buffer | ||
| - `__fill_buffer: (bufferPtr: u32) => void` | ||
| - A helper function that copies a prepared buffer, of the data host needs to send to the Wasm module, to the provided pointer (`bufferPtr`) in shared memory. | ||
| - *Params:* | ||
| - `bufferPtr(u32)` is pointer to the empty allocated buffer in shared memory. | ||
|
|
||
| #### Invocation | ||
|
|
||
| Invocation is a process of calling any functions defined in the Wasm module directly from the Host. | ||
|
|
||
| To perform an invocation, one must provide Invocation options which consists of the function name and arguments. Before passing these options to the Wasm module, host must encode it into an invocation options buffer. The function arguments are serialized into a buffer using MsgPack. Then the invoking function name is UTF-8 encoded and concatenated with the encoded function name length and the arguments buffer into an invocation options buffer. | ||
|
|
||
| The host can call the `_invoke` export with the length of the invocation options buffer. | ||
|
|
||
| **Invocation options buffer:** | ||
|
|
||
| | funcNameLen | funcName | argsBuffer | | ||
| | -------- | -------- | -------- | | ||
|
|
||
| The Wasm module can use the`__fill_buffer` import to fill an allocated invocation options buffer. | ||
|
|
||
| Once the invocation completes, the Wasm module returns the response buffer pointer. | ||
|
|
||
| The response buffer is a helper buffer used to encode the pointer and length of the invocation result buffer. | ||
|
|
||
| **Response buffer:** | ||
|
|
||
| | resultBufferLength | resultBufferPointer | | ||
| | -------- | -------- | | ||
|
|
||
| The result buffer contains the Msgpack encoded return value of the invoked Wasm function. | ||
|
|
||
| #### Subinvocation | ||
| Subinvocation is a process of calling any functions defined in the Host from the Wasm module. | ||
|
|
||
| Similar to an invocation, to perform a subinvocation, one must provide Invocation options which consists of function name and arguments. The Wasm module must encode it into an invocation options buffer. The function arguments are serialized into a buffer using MsgPack. Then the invoking function name is UTF-8 encoded and concatenated with the encoded function name length and the arguments buffer into an invocation options buffer. | ||
|
|
||
| The Wasm module can then call the `__subinvoke` import with the pointer and length of that buffer. | ||
|
|
||
| Once the subinvocation completes, the host returns the length of the result buffer. | ||
|
|
||
| The result buffer contains the Msgpack encoded return value of the subinvoked host function. | ||
|
|
||
|
|
||
| #### Invocation sequence diagram | ||
| [](https://mermaid.live/edit#pako:eNqFlVFvmzAQx7_KyU-JSqxBkpXykIdpmlZp2qb2YS9IkQOmtQY2MyZSVfW776gJ2EC2PKBg_j_f3f8O80oylXOSkIb_abnM-GfBnjSrUgn4Y5lRGu7lWf3m2i7VTBuRiZpJA19VY-arv1hTgV3uyc3hcNNpEwgpCHn-URuhZGM13QMU2OcRBUwCM1pZ2Ro2h5741BYecNPFSWBL4Sjew6wG3Tcu11bbaVBrpTsKrCxVxgxHUcG1TyyE6vE--T2GOhaiLI-nCf7T6PVCNR8pZKp-GXUBXEOQ2dgsFxK_pZBzxxXEnWwtoHlmQD-dVuFdGEAUbfGy3_chvivDQZ25BrthTOHRYMtsr4pWZl1DIEN7LKBqA6KApj1Zb-3qLLGYhkPDUHs_9my4G7yc-xnTqHN0CLJyIfQn8HYZmzrzOabbwSEX8TMZ4dGOC797_7fkxEKw_aTmB944kfDOq3nS3pjiVLhKrOuqu7eziZ2Q_4g79TqeTq-LjdO4UO9dP8YuEMB_8OlAL83Oh0nX7GZ-TZbmMl-eZMzti5Cieb46ygPqRe9ijyfNpYPCt9EnwgnhvIUPTe1DXfX9iRfRUYE-LRwT4dZ9v63S2XmJ2HnEpQfBWIBzoA0mDn3pj2XcZ097BQlIxXXFRI7fgtdOnxLzzCueEuwgyXnB2tKkJJVvKGWtUY8vMiOJ0S0PSFvnOKL9p4MkBSsb_vYXcHIEnw) | ||
|
|
||
| #### Glossary | ||
| - `invOpt`: Invocation options passed by Invoker which are the function name of the invoked Wasm function and its arguments. | ||
| - `invOptBuf`: Encoded invocation options buffer | ||
| - `invOptBufLen`: Length of the invocation options buffer | ||
| - `invOptBufPtr`: Reference pointer to the invocation options buffer allocated in the Wasm shared memory | ||
| - `subInvOpt`: Subinvocation options needed to subinvoke a Host function. They are the function name of the invoked Host function and its arguments. | ||
| - `subInvOptBuf`: Encoded subinvocation options buffer | ||
| - `subInvOptBufPtr`: Reference pointer to the Subinvocation options buffer allocated in the Wasm shared memory | ||
| - `subInvOptBufLen`: Length of the subinvocation options buffer | ||
| - `subInvResBufLen`: Length of the subinvocation result buffer | ||
| - `invRes`: Result of the invoked Wasm function. | ||
| - `invResBuf`: Encoded invocation result | ||
| - `invResBufPtr`: Reference pointer to the invocation result buffer allocated in the Wasm shared memory | ||
| - `invResBufLen`: Length of the invocation result buffer | ||
| - `invRspBuf`: Invocation response buffer which contains the pointer and length of the result buffer. | ||
| - `invRspBufPtr`: Reference pointer to the invocation response buffer | ||
| - `invRspBufLen`: Length of the invocation response buffer | ||
|
|
||
| #### Summary | ||
|
|
||
| 1. Invoker calls the host with invocation options(`invOpt`) which consists of the name of a Wasm module function and its arguments. | ||
| 2. The host encodes invocation options (`invOpt`) into an invocation options buffer(`invOptBuf`). | ||
| 3. The host calls the `_invoke` Wasm export with the length of the invocation options buffer(`invOptBufLen`) | ||
| 4. The Wasm module allocates a new invocation options buffer(`invOptBuf`) in the shared memory. This will be used to store the original invocation options buffer(`invOptbuf`), that exists inside the host, for use in the Wasm module. | ||
| 5. The Wasm module calls `__fill_buffer` with the pointer to the newly allocated invocation options buffer(`invOptBufPtr`). | ||
| 6. The host copies the invocation options buffer(`invOptBuf`) to the given pointer in the shared Wasm memory. | ||
| 7. After the call to `__fill_buffer`, the Wasm module reads and decodes the invocation options buffer (`invOptBuf`). | ||
| 8. The Wasm module calls the requested Wasm module function with the given arguments. | ||
| - If the invoked Wasm module function needs to subinvoke a function defined in the host, It performs the subinvocation with following steps | ||
| 1. The Wasm module encodes the subinvocation options (`subInvOpt`) into a subinvocation options buffer (`subInvOptBuf`). | ||
| 2. The Wasm module calls the imported `__subinvoke` function with the pointer and length to this buffer. | ||
| 3. The host reads and decodes the subinvocation options buffer(`subInvOptBuf`) from shared memory. | ||
| 4. The host calls the requested host function with the given arguments from the decoded subinvocation options(`subInvOpt`) | ||
| 5. Host will get the result of the subinvoked function(`subInvRes`) and encode it into a buffer(`subInvResBuf`) | ||
| 6. Host returns the length of the subinvocation result buffer(`subInvResBufLen`) as a result of the `__subinvoke` function. | ||
| 7. The Wasm module allocates a new subinvocation result buffer(`subInvResBuf`) in the shared memory with the given length(`subInvResBuflen`). This will be used to store the original subinvocation result buffer(`subInvResBuf`), that exists inside the host, for use in the Wasm module. | ||
| 8. The Wasm module calls the `__fill_buffer` with the pointer to the newly allocated subinvocation result buffer(`subInvResBuf`) | ||
| 9. The host copies the subinvocation result buffer(`subInvResBuf`) to the given pointer in shared memory. | ||
| 10. After the call to `__fill_buffer`, the Wasm module reads and decodes the subinvocation result buffer(`subInvResBuf`) from shared memory and can use it wherever needed. | ||
| 9. After the Wasm module finish execution of the invoked Wasm function, it receives the invocation result(`invRes`) as return value of the invoked function. | ||
| 10. The Wasm module encodes the invocation result(`invRes`) into an invocation result buffer(`invResBuf`) | ||
| 11. The Wasm module then allocates a new invocation response buffer(`invRspBuf`) and stores the pointer(`invResPtr`) and length(`invResLen`) of the invocation result buffer inside. | ||
| 12. The Wasm module returns the pointer of the invocation response buffer(`invRspPtr`) to the Host. | ||
| 13. The host reads(from shared memory) and decodes the invocation response buffer. | ||
| 14. The host uses the pointer and length of the invocation result buffer from the response buffer to read and decode the invocation result buffer into the invocation result. | ||
| 15. The host returns the invocation result to the invoker. | ||
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.
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 function feels too generic, and lacks context as to "what buffer is being filled". I think we could add a "bufferId" alongside the "bufferPtr" here. Also would need to add "bufferId" alongside the "bufferLen" in the _invoke export.
Uh oh!
There was an error while loading. Please reload this page.
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.
Reworded this a bit. But it is still a generic function, it can be either the
invOptBufferorsubInvResBufferthat the host is sending to the wasm module. It doesn't need an ID to identify it because there can be only one type depending on contextThere 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 function can also be named
load_bufferWhat do you guys prefer:
fill_buffer 🍏vsload_buffer 🍎