Skip to content
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ The engine uses the name as the state namespace, and it refuses a missing, empty
cargo run -p nexum-cli -- target/wasm32-wasip2/release/example.wasm modules/example/component.toml
```

A module that subscribes to `block` or `chain-log` events needs its chain declared in `engine.toml`, or the engine refuses to boot.
A module that declares a `block` or `event` trigger needs its chain declared in `engine.toml`, or the engine refuses to boot.
The smallest working stanza is:

```toml
Expand All @@ -57,7 +57,7 @@ rpc_url = "http://localhost:8545"
```

`http(s)://` URLs are not dialled at boot; `ws(s)://` URLs are.
The example module declares no subscriptions, so `just run` needs no `engine.toml`; the modules under `modules/examples/` and `modules/fixtures/` do.
The example module declares no triggers, so `just run` needs no `engine.toml`; the modules under `modules/examples/` and `modules/fixtures/` do.

## Component integrity

Expand Down
2 changes: 1 addition & 1 deletion crates/nexum-module-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ edition.workspace = true
rust-version.workspace = true
license.workspace = true
repository.workspace = true
description = "Proc-macro glue for nexum runtime modules: #[module] emits the per-cdylib wit-bindgen, host adapter, event dispatch, and export."
description = "Proc-macro glue for nexum runtime modules: #[module] emits the per-cdylib wit-bindgen, host adapter, trigger dispatch, and export."

[lib]
proc-macro = true
Expand Down
217 changes: 114 additions & 103 deletions crates/nexum-module-macros/src/lib.rs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
//! `subscribes()` with no events is rejected: an empty list would pin
//! `sol_events()` with no events is rejected: an empty list would pin
//! nothing while looking like it does.

use nexum_module_macros::module;

struct Alerts;

#[module(subscribes())]
#[module(sol_events())]
impl Alerts {
fn on_chain_logs(_payload: u64) -> Result<(), ()> {
fn on_event(_payload: u64) -> Result<(), ()> {
Ok(())
}
}
Expand Down
5 changes: 5 additions & 0 deletions crates/nexum-module-macros/tests/ui/empty_sol_events.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error: `sol_events(...)` must name at least one event type
--> tests/ui/empty_sol_events.rs:8:10
|
8 | #[module(sol_events())]
| ^^^^^^^^^^
5 changes: 0 additions & 5 deletions crates/nexum-module-macros/tests/ui/empty_subscribes.stderr

This file was deleted.

2 changes: 1 addition & 1 deletion crates/nexum-module-macros/tests/ui/generic_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ struct Alerts<T>(T);

#[module]
impl<T> Alerts<T> {
fn on_tick(_payload: u64) -> Result<(), ()> {
fn on_schedule(_payload: u64) -> Result<(), ()> {
Ok(())
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/nexum-module-macros/tests/ui/no_handlers.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: #[nexum_sdk::module] found no recognized handlers on this impl; define at least one of `init`, `on_block`, `on_chain_logs`, `on_tick`, `on_custom`
error: #[nexum_sdk::module] found no recognized handlers on this impl; define at least one of `init`, `on_block`, `on_event`, `on_schedule`, `on_extension`
--> tests/ui/no_handlers.rs:9:6
|
9 | impl Alerts {
Expand Down
2 changes: 1 addition & 1 deletion crates/nexum-module-macros/tests/ui/non_ident_argument.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ struct Alerts;

#[module(42)]
impl Alerts {
fn on_tick(_payload: u64) -> Result<(), ()> {
fn on_schedule(_payload: u64) -> Result<(), ()> {
Ok(())
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: expected `subscribes(EventType, ...)` or no arguments
error: expected `sol_events(EventType, ...)` or no arguments
--> tests/ui/non_ident_argument.rs:7:10
|
7 | #[module(42)]
Expand Down
14 changes: 14 additions & 0 deletions crates/nexum-module-macros/tests/ui/tokens_after_sol_events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//! Nothing may follow the `sol_events(...)` list.

use nexum_module_macros::module;

struct Alerts;

#[module(sol_events(Transfer), extra)]
impl Alerts {
fn on_event(_payload: u64) -> Result<(), ()> {
Ok(())
}
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
error: unexpected tokens after `sol_events(...)`
--> tests/ui/tokens_after_sol_events.rs:7:30
|
7 | #[module(sol_events(Transfer), extra)]
| ^
14 changes: 0 additions & 14 deletions crates/nexum-module-macros/tests/ui/tokens_after_subscribes.rs

This file was deleted.

This file was deleted.

4 changes: 2 additions & 2 deletions crates/nexum-module-macros/tests/ui/unknown_argument.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
//! The only recognized attribute argument is `subscribes(...)`.
//! The only recognized attribute argument is `sol_events(...)`.

use nexum_module_macros::module;

struct Alerts;

#[module(emits(Transfer))]
impl Alerts {
fn on_tick(_payload: u64) -> Result<(), ()> {
fn on_schedule(_payload: u64) -> Result<(), ()> {
Ok(())
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: #[nexum_sdk::module] takes no arguments except `subscribes(EventType, ...)`
error: #[nexum_sdk::module] takes no arguments except `sol_events(EventType, ...)`
--> tests/ui/unknown_argument.rs:7:10
|
7 | #[module(emits(Transfer))]
Expand Down
2 changes: 1 addition & 1 deletion crates/nexum-module-macros/tests/ui/unknown_handler.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: `on_blocks` is not a recognized #[nexum_sdk::module] handler; expected one of ["init", "on_block", "on_chain_logs", "on_tick", "on_custom"] (rename helpers so they do not start with `on_`)
error: `on_blocks` is not a recognized #[nexum_sdk::module] handler; expected one of ["init", "on_block", "on_event", "on_schedule", "on_extension"] (rename helpers so they do not start with `on_`)
--> tests/ui/unknown_handler.rs:10:8
|
10 | fn on_blocks(_payload: u64) -> Result<(), ()> {
Expand Down
2 changes: 1 addition & 1 deletion crates/nexum-module-macros/tests/ui/unnamed_self_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ struct Alerts;

#[module]
impl &Alerts {
fn on_tick(_payload: u64) -> Result<(), ()> {
fn on_schedule(_payload: u64) -> Result<(), ()> {
Ok(())
}
}
Expand Down
8 changes: 4 additions & 4 deletions crates/nexum-runtime/src/bindings.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
//! WIT bindings generated by `wasmtime::component::bindgen!`.
//!
//! Binds the `nexum:host/event-module` world (the six core primitives).
//! Binds the `nexum:host/trigger-module` world (the six core primitives).
//! Outbound HTTP is wasi:http, linked separately; clocks are ambient
//! wasi:clocks. `nexum:host` is a leaf package: the host `event` variant
//! wasi:clocks. `nexum:host` is a leaf package: the host `trigger` variant
//! carries a status transition as opaque bytes. An extension remaps onto these
//! shared interfaces with `with`, so the `Host` impls and `fault` type its
//! components see are the ones the core host constructs. `PartialEq` is derived
//! so extension services can compare event payloads.
//! so extension services can compare trigger payloads.

// Every item in this module is macro output, so a doc comment has nowhere
// to attach. The module doc above stands for the world it binds.
#![allow(missing_docs)]

wasmtime::component::bindgen!({
path: ["../../wit/nexum-host"],
world: "nexum:host/event-module",
world: "nexum:host/trigger-module",
imports: { default: async },
exports: { default: async },
additional_derives: [PartialEq],
Expand Down
48 changes: 25 additions & 23 deletions crates/nexum-runtime/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
//! component builders, add-ons) through a type-state chain;
//! [`ReadyBuilder::launch`] opens the backends and hands off to
//! [`AssembledRuntime::launch`], which installs add-ons, builds the engine and
//! linker, boots the supervisor, opens subscriptions, spawns the event loop,
//! and returns a [`RuntimeHandle`]. [`RuntimeBuilder::runtime`] binds a
//! linker, boots the supervisor, opens the trigger sources, spawns the event
//! loop, and returns a [`RuntimeHandle`]. [`RuntimeBuilder::runtime`] binds a
//! [`Runtime`] preset for the common case.

use std::future::IntoFuture;
Expand All @@ -24,7 +24,7 @@ use crate::engine_config::{EngineConfig, ModuleEntry, PolicySection};
use crate::host::component::{
BuilderContext, ComponentBuilder, Components, ComponentsBuilder, RuntimeTypes,
};
use crate::host::extension::{self, EventSources, Extension};
use crate::host::extension::{self, Extension, SourceContext};
use crate::host::logs::LogPipeline;
use crate::host::provider_pool::ProviderPool;
use crate::preset::Runtime;
Expand Down Expand Up @@ -69,14 +69,14 @@ pub enum LaunchRefusal {
/// How many were tried.
modules: usize,
},
/// Some modules survived `init`, but no surviving one holds a
/// subscription, so the engine would run and never be woken.
/// Some modules survived `init`, but no surviving one declares a
/// trigger, so the engine would run and never be woken.
#[error(
"every declared [[subscription]] belongs to an init-failed module - \
"every declared [[trigger]] belongs to an init-failed module - \
the engine would idle with nothing to run; fix or remove the \
failing module(s)"
)]
DeadHoldSubs,
DeadHoldTriggers,
}

/// Ambient inputs the launcher reads.
Expand Down Expand Up @@ -296,7 +296,7 @@ impl<T: RuntimeTypes> AssembledRuntime<T> {
};

let alive = supervisor.alive_count();
let plan = supervisor.subscription_plan();
let plan = supervisor.trigger_plan();
info!(
modules = supervisor.module_count(),
alive,
Expand Down Expand Up @@ -339,29 +339,31 @@ impl<T: RuntimeTypes> AssembledRuntime<T> {
// The handle keeps the log read side reachable after launch consumes
// the components.
let logs = components.logs.clone();
// Extension event sources open only for subscription kinds some
// live module declares; an extension returns no stream when it has
// nothing to observe.
// Extension sources open only for trigger kinds some live module
// declares; an extension returns no stream when it has nothing to
// observe.
let mut reconnect_tasks = TaskSet::new();
let mut extension_streams = Vec::new();
{
let mut sources = EventSources::new(
let mut sources = SourceContext::new(
engine_cfg,
&plan.extension_kinds,
&executor,
&mut reconnect_tasks,
);
for ext in &extensions {
extension_streams.extend(ext.events(&mut sources)?);
extension_streams.extend(ext.open_sources(&mut sources)?);
}
}

match plan.viability(extension_streams.len()) {
Viability::DeadHoldSubs => return Err(refuse_launch(LaunchRefusal::DeadHoldSubs)),
Viability::DeadHoldTriggers => {
return Err(refuse_launch(LaunchRefusal::DeadHoldTriggers));
}
Viability::Nothing => {
// Nothing to drive: return a handle whose event loop is
// already complete so `wait` resolves immediately.
info!("no [[subscription]] entries - engine has nothing to run; exiting");
info!("no [[trigger]] entries - engine has nothing to run; exiting");
let event_loop = executor.spawn(async { TaskExit::ReceiverGone });
return Ok(RuntimeHandle {
event_loop,
Expand All @@ -374,9 +376,9 @@ impl<T: RuntimeTypes> AssembledRuntime<T> {
Viability::Live => {}
}

// Open per-chain block subscriptions + per-module chain-log
// subscriptions through the executor, then drive them in the event
// loop until shutdown.
// Open per-chain block streams + per-module chain-log streams
// through the executor, then drive them in the event loop until
// shutdown.
let block_streams = event_loop::open_block_streams(
&components.chain,
&plan.block_chains,
Expand All @@ -385,7 +387,7 @@ impl<T: RuntimeTypes> AssembledRuntime<T> {
);
let chain_log_streams = event_loop::open_chain_log_streams(
&components.chain,
plan.chain_log_subs,
plan.event_triggers,
&executor,
&mut reconnect_tasks,
);
Expand Down Expand Up @@ -1175,7 +1177,7 @@ mod tests {
let manifest = TestManifest::new("price-alert")
.cap("logging")
.cap("chain")
.block_sub(11_155_111)
.block_trigger(11_155_111)
.config(
"oracle_address",
"0x694AA1769357215DE4FAC081bf1f309aDC325306",
Expand Down Expand Up @@ -1210,14 +1212,14 @@ mod tests {
}

#[tokio::test]
async fn launch_bails_on_an_unconfigured_chain_subscription() {
async fn launch_bails_on_an_unconfigured_chain_trigger() {
let dir = tempfile::tempdir().expect("tempdir");
let wasm = dir.path().join("missing.wasm");
let manifest = dir.path().join("component.toml");
std::fs::write(
&manifest,
"[component]\nname = \"example\"\n\n[dependencies]\nlogging = {}\n\n\
[[subscription]]\nkind = \"block\"\nchain_id = 424242\n",
[[trigger]]\non = \"block\"\nchain_id = 424242\n",
)
.expect("write manifest");

Expand All @@ -1235,7 +1237,7 @@ mod tests {
.launch()
.await
{
Ok(_) => panic!("an unconfigured chain subscription must abort launch"),
Ok(_) => panic!("an unconfigured chain trigger must abort launch"),
Err(err) => err,
};
Refusal::from(err).variant::<BootRefusal>(|e| {
Expand Down
Loading
Loading