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

update wasmtime from from 14.0.4 to 18.0.2 and follow wasmtimes fuel API changes #531

Merged
merged 1 commit into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,24 @@ Types of changes
- `Fixed` for any bug fixes.
- `Security` in case of vulnerabilities.

## unreleased
## [0.9.0 - unreleased]

put your changes here
Wasmtime rewrote their fuel-related API and simplified it. To remain consistent with Wasmtime, we follow this change in this release. A Wasmex `Store` now only implements `set_fuel/2` and `get_fuel/1`. All other methods are removed with this release.

The underlying implementation of the fuel system got rewritten as well. If you are using fuel in your app,
please check your fuel consumption values.

* Thanks to @RoyalIcing for helping us keeping our dependencies up to date for this release 💜

### Added

* official support for Elixir 1.15 and 1.16
* fuel-related API got rewritten, because the underlying Wasm library (wasmtime) changed their API and we want to be consistent. Added `Store.get_fuel/1` and `Store.set_fuel/2` which is a much simpler API than before.

### Removed

* removed support for Elixir 1.12
* with the fuel-related API changed, the existing methods on `Store` (`consume_fuel`, `fuel_remaining`, `add_fuel`) were removed. Please call `set_fuel/2` and `get_fuel/1` instead.

### Changed

Expand Down
2 changes: 1 addition & 1 deletion lib/wasmex/engine_config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ defmodule Wasmex.EngineConfig do

Note that a `Wasmex.Store` starts with no fuel, so if you enable this option
you'll have to be sure to pour some fuel into `Wasmex.Store` before
executing some code. See `Wasmex.StoreOrCaller.add_fuel/2`.
executing some code. See `Wasmex.StoreOrCaller.set_fuel/2`.

## Example

Expand Down
5 changes: 2 additions & 3 deletions lib/wasmex/native.ex
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,8 @@ defmodule Wasmex.Native do
def store_new(_store_limits, _engine_resource), do: error()
def store_new_wasi(_wasi_options, _store_limits, _engine_resource), do: error()

def store_or_caller_add_fuel(_store_or_caller_resource, _fuel), do: error()
def store_or_caller_consume_fuel(_store_or_caller_resource, _fuel), do: error()
def store_or_caller_fuel_consumed(_store_or_caller_resource), do: error()
def store_or_caller_get_fuel(_store_or_caller_resource), do: error()
def store_or_caller_set_fuel(_store_or_caller_resource, _fuel), do: error()

# When the NIF is loaded, it will override functions in this module.
# Calling error is handles the case when the nif could not be loaded.
Expand Down
89 changes: 11 additions & 78 deletions lib/wasmex/store_or_caller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ defmodule Wasmex.StoreOrCaller do
end

@doc ~S"""
Adds fuel to this Store for Wasm to consume while executing.
Sets fuel to for Wasm to consume while executing.

For this method to work, fuel consumption must be enabled via
`Wasmex.EngineConfig.consume_fuel/2. By default a `Wasmex.Store`
Expand All @@ -58,100 +58,33 @@ defmodule Wasmex.StoreOrCaller do

iex> {:ok, engine} = Wasmex.Engine.new(%Wasmex.EngineConfig{consume_fuel: true})
iex> {:ok, store} = Wasmex.Store.new(nil, engine)
iex> Wasmex.StoreOrCaller.add_fuel(store, 10)
iex> Wasmex.StoreOrCaller.set_fuel(store, 10)
:ok
"""
@spec add_fuel(__MODULE__.t(), pos_integer()) :: :ok | {:error, binary()}
def add_fuel(%__MODULE__{resource: resource}, fuel) do
case Wasmex.Native.store_or_caller_add_fuel(resource, fuel) do
@spec set_fuel(__MODULE__.t(), pos_integer()) :: :ok | {:error, binary()}
def set_fuel(%__MODULE__{resource: resource}, fuel) do
case Wasmex.Native.store_or_caller_set_fuel(resource, fuel) do
{} -> :ok
{:error, reason} -> {:error, reason}
end
end

@doc ~S"""
Synthetically consumes fuel from this Store.

For this method to work fuel, consumption must be enabled via
`Wasmex.EngineConfig.consume_fuel/2`.

WebAssembly execution will automatically consume fuel but if so desired
the embedder can also consume fuel manually to account for relative
costs of host functions, for example.

This function will attempt to consume `fuel` units of fuel from within
this store. If the remaining amount of fuel allows this then `{:ok, N}`
is returned where `N` is the amount of remaining fuel. Otherwise an
error is returned and no fuel is consumed.

## Errors

This function will return an error either if fuel consumption is not
enabled via `Wasmex.EngineConfig.consume_fuel/2` or if `fuel` exceeds
the amount of remaining fuel within this store.

## Examples

iex> {:ok, engine} = Wasmex.Engine.new(%Wasmex.EngineConfig{consume_fuel: true})
iex> {:ok, store} = Wasmex.Store.new(nil, engine)
iex> Wasmex.StoreOrCaller.add_fuel(store, 10)
iex> Wasmex.StoreOrCaller.fuel_remaining(store)
{:ok, 10}
"""
@spec consume_fuel(__MODULE__.t(), pos_integer() | 0) ::
{:ok, pos_integer()} | {:error, binary()}
def consume_fuel(%__MODULE__{resource: resource}, fuel) do
case Wasmex.Native.store_or_caller_consume_fuel(resource, fuel) do
{:error, reason} -> {:error, reason}
fuel_remaining -> {:ok, fuel_remaining}
end
end

@doc ~S"""
Returns the amount of fuel available for future execution of this store.

## Examples

iex> {:ok, engine} = Wasmex.Engine.new(%Wasmex.EngineConfig{consume_fuel: true})
iex> {:ok, store} = Wasmex.Store.new(nil, engine)
iex> Wasmex.StoreOrCaller.add_fuel(store, 10)
iex> Wasmex.StoreOrCaller.fuel_remaining(store)
iex> Wasmex.StoreOrCaller.set_fuel(store, 10)
iex> Wasmex.StoreOrCaller.get_fuel(store)
{:ok, 10}
"""
@spec fuel_remaining(__MODULE__.t()) :: {:ok, pos_integer()} | {:error, binary()}
def fuel_remaining(%__MODULE__{} = store_or_caller) do
consume_fuel(store_or_caller, 0)
end

@doc ~S"""
Returns the amount of fuel consumed by this store's execution so far.

Note that fuel, if enabled, must be initially added via
`Wasmex.StoreOrCaller.add_fuel/2`.

## Errors

If fuel consumption is not enabled via
`Wasmex.EngineConfig.consume_fuel/2` then this function will return
an error tuple.

## Examples

iex> {:ok, engine} = Wasmex.Engine.new(%Wasmex.EngineConfig{consume_fuel: true})
iex> {:ok, store} = Wasmex.Store.new(nil, engine)
iex> Wasmex.StoreOrCaller.fuel_consumed(store)
{:ok, 0}
iex> Wasmex.StoreOrCaller.add_fuel(store, 10)
iex> {:ok, _fuel} = Wasmex.StoreOrCaller.consume_fuel(store, 8)
iex> Wasmex.StoreOrCaller.fuel_consumed(store)
{:ok, 8}
"""
@spec fuel_consumed(__MODULE__.t()) :: {:ok, pos_integer()} | {:error, binary()}
def fuel_consumed(%__MODULE__{resource: resource}) do
case Wasmex.Native.store_or_caller_fuel_consumed(resource) do
@spec get_fuel(__MODULE__.t()) :: {:ok, pos_integer()} | {:error, binary()}
def get_fuel(%__MODULE__{resource: resource}) do
case Wasmex.Native.store_or_caller_get_fuel(resource) do
{:error, reason} -> {:error, reason}
nil -> {:error, "Could not consume fuel: fuel is not configured in this store"}
fuel_consumed -> {:ok, fuel_consumed}
get_fuel -> {:ok, get_fuel}
end
end
end
Expand Down
Loading
Loading