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

Forkless state transition #1547

Closed
xgreenx opened this issue Dec 14, 2023 · 0 comments · Fixed by #1716
Closed

Forkless state transition #1547

xgreenx opened this issue Dec 14, 2023 · 0 comments · Fixed by #1716
Assignees
Labels
SDK team The issue is ready to be addressed by SDK team upgradability

Comments

@xgreenx
Copy link
Collaborator

xgreenx commented Dec 14, 2023

Implement the WASM version of the state transition function that can be represented by the byte code and shared with the rest of the network.

The WASM state transition function should generate the same changes as the std version.

@xgreenx xgreenx added SDK team The issue is ready to be addressed by SDK team upgradability labels Dec 14, 2023
@xgreenx xgreenx self-assigned this Dec 14, 2023
xgreenx added a commit that referenced this issue Mar 26, 2024
Closes #1547

## Change overview

The change adds the WASM version of the `fuel_core_executor::Executor`
and the upgradable executor that works with native(std) and WASM(no-std)
versions of the executor. Currently, it uses either the WASM or the std
version. But in the follow-up PRs it will decide which version to use
based on the block header. For now, this behavior is controlled by the
"wasm-executor" feature. The CI runs tests two times, one with the WASM
executor and the second with std, to verify that behaviors are the same.

## Details on how WASM integration is done

The `fuel-core-upgradable-executor` uses the `wasmtime` library to
compile and run the WASM bytecode. The `wastime::Engine` allows
customization of how the `wastime::Module` compiles the bytecode. For
simplicity, we are using the default configuration that works on all
platforms for now, but later, it is possible to do more specific
compilation.

We are using `wastime::Linker` to add host functions that can be called
from the WASM runtime via `extern "C"` API:

```rust
#[link(wasm_import_module = "host_v0")]
extern "C" {
    /// Returns the size of the value from the storage.
    pub(crate) fn storage_size_of_value(
        key_ptr: Ptr32<[u8]>,
        key_len: u32,
        column: u32,
    ) -> u64;

    /// Returns the value from the storage.
    pub(crate) fn storage_get(
        key_ptr: Ptr32<[u8]>,
        key_len: u32,
        column: u32,
        out_ptr: Ptr32Mut<[u8]>,
        out_len: u32,
    ) -> ReturnResult;
}
```

The host functions are closures that capture data required for the work,
such as the storage or relayer. Host functions have access to the
`ExecutionState`, which accumulates intermediate data.

Data is passed between the host and runtime through memory, where one
side gives the pointer where data should be stored, and another side
writes the memory using this pointer and the size. The host is not
responsible for allocating and deallocating memory; the memory
management is done within WASM runtime. Currently, when we return
something from the runtime to the host, we "leak" it to avoid
deallocation. It allows the host to read the value from the memory.

Side changes:
- The coinbase contract id is not a part of the `Config` anymore. It is
part of the `Components` and seats along with the `gas_price` because it
is defined by the block producer and can always be changed on the fly.
- The usage of `anyhow::Error` in the `ExecutorError` was replaced by
`String` because it doesn't implement `serde` ser/des.
- The `ExecutionOptions`, `WriteOperation`, `ExecutionResult`,
`TransactionExecutionResult`, `TransactionExecutionStatus`,
`ExecutorError`, and `TransactionValidityError` support `serde` ser/des.
- The `fuel-core-executor` only provides the `ExecutionInstance` without
`Executor`. The logic of the `Executor` was moved to the
`fuel-core-upgradable-executor`.

---------

Co-authored-by: Voxelot <[email protected]>
crypto523 added a commit to crypto523/fuel-core that referenced this issue Oct 7, 2024
Closes FuelLabs/fuel-core#1547

## Change overview

The change adds the WASM version of the `fuel_core_executor::Executor`
and the upgradable executor that works with native(std) and WASM(no-std)
versions of the executor. Currently, it uses either the WASM or the std
version. But in the follow-up PRs it will decide which version to use
based on the block header. For now, this behavior is controlled by the
"wasm-executor" feature. The CI runs tests two times, one with the WASM
executor and the second with std, to verify that behaviors are the same.

## Details on how WASM integration is done

The `fuel-core-upgradable-executor` uses the `wasmtime` library to
compile and run the WASM bytecode. The `wastime::Engine` allows
customization of how the `wastime::Module` compiles the bytecode. For
simplicity, we are using the default configuration that works on all
platforms for now, but later, it is possible to do more specific
compilation.

We are using `wastime::Linker` to add host functions that can be called
from the WASM runtime via `extern "C"` API:

```rust
#[link(wasm_import_module = "host_v0")]
extern "C" {
    /// Returns the size of the value from the storage.
    pub(crate) fn storage_size_of_value(
        key_ptr: Ptr32<[u8]>,
        key_len: u32,
        column: u32,
    ) -> u64;

    /// Returns the value from the storage.
    pub(crate) fn storage_get(
        key_ptr: Ptr32<[u8]>,
        key_len: u32,
        column: u32,
        out_ptr: Ptr32Mut<[u8]>,
        out_len: u32,
    ) -> ReturnResult;
}
```

The host functions are closures that capture data required for the work,
such as the storage or relayer. Host functions have access to the
`ExecutionState`, which accumulates intermediate data.

Data is passed between the host and runtime through memory, where one
side gives the pointer where data should be stored, and another side
writes the memory using this pointer and the size. The host is not
responsible for allocating and deallocating memory; the memory
management is done within WASM runtime. Currently, when we return
something from the runtime to the host, we "leak" it to avoid
deallocation. It allows the host to read the value from the memory.

Side changes:
- The coinbase contract id is not a part of the `Config` anymore. It is
part of the `Components` and seats along with the `gas_price` because it
is defined by the block producer and can always be changed on the fly.
- The usage of `anyhow::Error` in the `ExecutorError` was replaced by
`String` because it doesn't implement `serde` ser/des.
- The `ExecutionOptions`, `WriteOperation`, `ExecutionResult`,
`TransactionExecutionResult`, `TransactionExecutionStatus`,
`ExecutorError`, and `TransactionValidityError` support `serde` ser/des.
- The `fuel-core-executor` only provides the `ExecutionInstance` without
`Executor`. The logic of the `Executor` was moved to the
`fuel-core-upgradable-executor`.

---------

Co-authored-by: Voxelot <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
SDK team The issue is ready to be addressed by SDK team upgradability
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant