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

feat: Update wasm::Module to enable wasm component model [try 2] #123

Merged
merged 22 commits into from
Feb 13, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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