Skip to content

Commit

Permalink
update wasmtime from from 14.0.4 to 18.0.2 and follow wasmtimes fuel …
Browse files Browse the repository at this point in the history
…API changes
  • Loading branch information
tessi committed Mar 6, 2024
1 parent 59d0926 commit ba48cea
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 661 deletions.
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

0 comments on commit ba48cea

Please sign in to comment.