Skip to content

Commit

Permalink
feat: Update wasm::Module to enable wasm component model [try 2] (#123)
Browse files Browse the repository at this point in the history
* add HermesEventPayload trait, update wasm Module

* refactor

* refactor

* update test

* update

* add docs

* update

* fix spelling

* update

* refactor Context

* refactor

* update wasm::module

* fix formating

* commented out test

* move event mod under the event_queue mod

* move bindings mod to the separate file

* move Context and Statefull to another module

* update error handling

* fix docs

* update errors
  • Loading branch information
Mr-Leshiy committed Feb 13, 2024
1 parent d6edf48 commit 1fdb165
Show file tree
Hide file tree
Showing 41 changed files with 645 additions and 542 deletions.
1 change: 1 addition & 0 deletions hermes/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,4 @@ pallas-hardano = { version = "0.22.0" }
wasmtime = "17.0.0"
rusty_ulid = "2.0.0"
anyhow = "1.0.71"
thiserror = "1.0.56"
1 change: 1 addition & 0 deletions hermes/bin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ workspace = true
wasmtime = { workspace = true, features = ["component-model"] }
rusty_ulid = { workspace = true }
anyhow = { workspace = true }
thiserror = { workspace = true }
20 changes: 20 additions & 0 deletions hermes/bin/src/event_queue/event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//! Hermes event definition

use crate::wasm::module::ModuleInstance;

/// A trait for defining the behavior of a Hermes event.
pub trait HermesEventPayload {
/// Returns the name of the event associated with the payload.
fn event_name(&self) -> &str;

/// Executes the behavior associated with the payload, using the provided executor.
///
/// # Arguments
///
/// * `executor` - The executor to use for executing the payload's behavior.
///
/// # Returns
///
/// An `anyhow::Result` indicating the success or failure of the payload execution.
fn execute(&self, executor: &mut ModuleInstance) -> anyhow::Result<()>;
}
3 changes: 3 additions & 0 deletions hermes/bin/src/event_queue/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//! Hermes event queue implementation.

pub(crate) mod event;
3 changes: 3 additions & 0 deletions hermes/bin/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
//! Intentionally empty
//! This file exists, so that doc tests can be used inside binary crates.

mod event_queue;
mod runtime;
mod state;
mod wasm;
2 changes: 2 additions & 0 deletions hermes/bin/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! The Hermes Node.

mod event_queue;
mod runtime;
mod state;
mod wasm;

fn main() {
Expand Down
14 changes: 14 additions & 0 deletions hermes/bin/src/runtime/extensions/bindings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//! Hermes `wasmtime::component::bindgen` generated code
//!
//! *Note*
//! Inspect the generated code with:
//! `cargo expand --bin hermes runtime::extensions::bindings`

#![allow(clippy::indexing_slicing)]

use wasmtime::component::bindgen;

bindgen!({
world: "hermes",
path: "../../wasm/wasi/wit",
});
77 changes: 17 additions & 60 deletions hermes/bin/src/runtime/extensions/mod.rs
Original file line number Diff line number Diff line change
@@ -1,72 +1,27 @@
//! Hermes runtime extensions
//!
//! *Note*
//! Inspect the generated code with:
//! ```
//! cargo expand --bin hermes runtime::extensions
//! ```
#![allow(clippy::indexing_slicing)]

use wasmtime::{
component::{bindgen, Component, Linker},
component::{Component, Linker},
Config, Engine, Store,
};

use self::{
use self::bindings::{
exports::hermes::cardano::event_on_block::BlockSrc,
hermes::{
cardano::api::{CardanoBlock, CardanoBlockchainId, CardanoTxn},
cron::api::CronTagged,
},
};
use crate::{runtime, wasm::context::Context};
use crate::state::HermesState;

bindgen!({
world: "hermes",
path: "../../wasm/wasi/wit",
});

/// All Hermes runtime extensions states need to implement this.
pub(crate) trait Stateful {
/// Initial state for the given context
fn new(ctx: &Context) -> Self;
}

#[allow(dead_code)]
/// State for Hermes runtime
pub(crate) struct HermesState {
/// Hermes custom extensions state
pub hermes: runtime::host::hermes::State,

/// WASI standard extensions state
pub wasi: runtime::host::wasi::State,

/// The context of the wasm modules using this State.
pub ctx: Context,
}

impl Stateful for HermesState {
fn new(ctx: &Context) -> HermesState {
HermesState {
hermes: runtime::host::hermes::State::new(ctx),
wasi: runtime::host::wasi::State::new(ctx),
ctx: ctx.clone(),
}
}
}

#[allow(dead_code)]
/// Link a component to the Hermes runtime.
pub(crate) fn link_runtime(engine: &Engine) -> anyhow::Result<Linker<HermesState>> {
let mut linker = Linker::new(engine);
Hermes::add_to_linker(&mut linker, |state: &mut HermesState| state)?;

Ok(linker)
}
pub(crate) mod bindings;
pub(crate) mod state;

/// Example of how to call the autogenerated entry points
#[allow(dead_code)]
fn example() -> anyhow::Result<()> {
use crate::runtime::extensions::state::{Context, Stateful};

// Configure an `Engine` and compile the `Component` that is being run for
// the application.
let mut config = Config::new();
Expand All @@ -75,14 +30,14 @@ fn example() -> anyhow::Result<()> {
let component = Component::from_file(&engine, "./your-component.wasm")?;

// Instantiation of bindings always happens through a `Linker`.
// Configuration of the linker is done through a generated `add_to_linker`
// method on the bindings structure.
//
// Note that the closure provided here is a projection from `T` in
// `Store<T>` to `&mut U` where `U` implements the `HelloWorldImports`
// trait. In this case the `T`, `MyState`, is stored directly in the
// structure so no projection is necessary here.
let linker = link_runtime(&engine)?;
let mut linker = Linker::new(&engine);
bindings::Hermes::add_to_linker(&mut linker, |state: &mut HermesState| state)?;

let instance_pre = linker.instantiate_pre(&component)?;

// As with the core wasm API of Wasmtime instantiation occurs within a
Expand All @@ -96,10 +51,10 @@ fn example() -> anyhow::Result<()> {
);

//
let (bindings, _) = Hermes::instantiate_pre(&mut store, &instance_pre)?;
let (bindings, _) = bindings::Hermes::instantiate_pre(&mut store, &instance_pre)?;

// Show how we call the events in our API.
let _result = bindings.interface5.call_init(&mut store)?;
let _result = bindings.hermes_init_event().call_init(&mut store)?;

// HTTP API to be rewritten, but this is how its called.
// let arg1 = ??;
Expand Down Expand Up @@ -137,13 +92,15 @@ fn example() -> anyhow::Result<()> {
tag: "tag".to_string(),
};
let arg1 = false;
let _result = bindings.interface4.call_on_cron(&mut store, &arg0, arg1)?;
let _result = bindings
.hermes_cron_event()
.call_on_cron(&mut store, &arg0, arg1)?;

// Example of calling kv_update
let arg0 = "key";
let arg1 = hermes::kv_store::api::KvValues::KvString("value".to_string());
let arg1 = bindings::hermes::kv_store::api::KvValues::KvString("value".to_string());
bindings
.interface6
.hermes_kv_store_event()
.call_kv_update(&mut store, arg0, &arg1)?;

Ok(())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! WASM module's context implementation.
//! Hermes runtime extensions state.

use rusty_ulid::Ulid;

Expand Down Expand Up @@ -31,8 +31,8 @@ impl Context {
}

/// Increments the module's execution counter and sets the event name to be executed
pub(crate) fn use_for(&mut self, even_name: String) {
self.event_name = Some(even_name);
pub(crate) fn use_for(&mut self, event_name: String) {
self.event_name = Some(event_name);
self.counter += 1;
}

Expand Down Expand Up @@ -60,3 +60,9 @@ impl Context {
self.counter
}
}

/// All Hermes runtime extensions states need to implement this.
pub(crate) trait Stateful {
/// Initial state for the given context
fn new(ctx: &Context) -> Self;
}
11 changes: 8 additions & 3 deletions hermes/bin/src/runtime/host/hermes/binary/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
//! Host - CBOR implementations
#![allow(unused_variables)]

use crate::runtime::extensions::{hermes::binary::api::Host, HermesState, Stateful};
use crate::{
runtime::extensions::{
bindings::hermes::binary::api::Host,
state::{Context, Stateful},
},
state::HermesState,
};

/// State
pub(crate) struct State {}

impl Stateful for State {
fn new(_ctx: &crate::wasm::context::Context) -> Self {
fn new(_ctx: &Context) -> Self {
State {}
}
}
Expand Down
30 changes: 16 additions & 14 deletions hermes/bin/src/runtime/host/hermes/cardano/mod.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
//! Host - Cardano Blockchain implementations
#![allow(unused_variables)]

use crate::runtime::extensions::{
hermes::cardano::api::{
CardanoBlock, CardanoBlockchainId, CardanoTxn, FetchError, Host, Slot, TxnError,
UnsubscribeOptions,
use crate::{
runtime::extensions::{
bindings::hermes::cardano::api::{
CardanoBlock, CardanoBlockchainId, CardanoTxn, FetchError, Host, Slot, TxnError,
UnsubscribeOptions,
},
state::{Context, Stateful},
},
HermesState, Stateful,
state::HermesState,
};

/// State
pub(crate) struct State {}

impl Stateful for State {
fn new(_ctx: &crate::wasm::context::Context) -> Self {
fn new(_ctx: &Context) -> Self {
State {}
}
}
Expand Down Expand Up @@ -47,7 +49,7 @@ impl Host for HermesState {
/// `whence` == `stop` will prevent the blockchain syncing, and the caller will be
/// unsubscribed.
fn subscribe_blocks(
&mut self, net: CardanoBlockchainId, whence: Slot,
&mut self, _net: CardanoBlockchainId, _whence: Slot,
) -> wasmtime::Result<Result<u64, FetchError>> {
todo!()
}
Expand All @@ -72,7 +74,7 @@ impl Host for HermesState {
/// the last block received. This would result in the last block being sent as an
/// event twice,
/// once before the `stop` and once after the `continue`.
fn unsubscribe(&mut self, events: UnsubscribeOptions) -> wasmtime::Result<()> {
fn unsubscribe(&mut self, _events: UnsubscribeOptions) -> wasmtime::Result<()> {
todo!()
}

Expand All @@ -82,7 +84,7 @@ impl Host for HermesState {
/// **Parameters**
///
/// - `net` : The blockchain network to subscribe to txn events from.
fn subscribe_txn(&mut self, net: CardanoBlockchainId) -> wasmtime::Result<()> {
fn subscribe_txn(&mut self, _net: CardanoBlockchainId) -> wasmtime::Result<()> {
todo!()
}

Expand All @@ -99,7 +101,7 @@ impl Host for HermesState {
/// data from the rollback point. No action is required to actually follow the
/// rollback, unless the
/// default behavior is not desired.
fn subscribe_rollback(&mut self, net: CardanoBlockchainId) -> wasmtime::Result<()> {
fn subscribe_rollback(&mut self, _net: CardanoBlockchainId) -> wasmtime::Result<()> {
todo!()
}

Expand All @@ -124,7 +126,7 @@ impl Host for HermesState {
/// parallel
/// to automated block fetch.
fn fetch_block(
&mut self, net: CardanoBlockchainId, whence: Slot,
&mut self, _net: CardanoBlockchainId, _whence: Slot,
) -> wasmtime::Result<Result<CardanoBlock, FetchError>> {
todo!()
}
Expand All @@ -146,7 +148,7 @@ impl Host for HermesState {
/// This function exists to support `fetch-block`.
/// Transactions from subscribed block events, should be processed as transaction
/// events.
fn get_txns(&mut self, block: CardanoBlock) -> wasmtime::Result<Vec<CardanoTxn>> {
fn get_txns(&mut self, _block: CardanoBlock) -> wasmtime::Result<Vec<CardanoTxn>> {
todo!()
}

Expand All @@ -168,7 +170,7 @@ impl Host for HermesState {
/// This is proposed functionality, and is not yet active.
/// All calls to this function will return `post-txn-not-allowed` error.
fn post_txn(
&mut self, net: CardanoBlockchainId, txn: CardanoTxn,
&mut self, _net: CardanoBlockchainId, _txn: CardanoTxn,
) -> wasmtime::Result<Result<(), TxnError>> {
todo!()
}
Expand Down
11 changes: 8 additions & 3 deletions hermes/bin/src/runtime/host/hermes/cbor/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
//! Host - CBOR implementations
#![allow(unused_variables)]

use crate::runtime::extensions::{hermes::cbor::api::Host, HermesState, Stateful};
use crate::{
runtime::extensions::{
bindings::hermes::cbor::api::Host,
state::{Context, Stateful},
},
state::HermesState,
};

/// State
pub(crate) struct State {}

impl Stateful for State {
fn new(_ctx: &crate::wasm::context::Context) -> Self {
fn new(_ctx: &Context) -> Self {
State {}
}
}
Expand Down

0 comments on commit 1fdb165

Please sign in to comment.