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
44 changes: 21 additions & 23 deletions crates/bindings-csharp/Runtime/bindings.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,10 @@ static MonoArray* stdb_buffer_consume(Buffer buf);
// return out;
// }

__attribute__((import_module("spacetime"),
#define STDB_IMPORT_MODULE_MINOR(minor) "spacetime_6." #minor
#define STDB_IMPORT_MODULE STDB_IMPORT_MODULE_MINOR(0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: let's just inline the string here, same as Rust does. It's a bit weird to edit two parts of version in two places.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure 👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant inline minor into the same string too, so that it's just spacetime_6.0 like in Rust.


__attribute__((import_module(STDB_IMPORT_MODULE),
import_name("_get_table_id"))) extern uint16_t
_get_table_id(const char* name, size_t name_len, uint32_t* out);

Expand All @@ -117,7 +120,7 @@ static uint32_t stdb_get_table_id(MonoString* name_) {
return out;
}

__attribute__((import_module("spacetime"),
__attribute__((import_module(STDB_IMPORT_MODULE),
import_name("_create_index"))) extern uint16_t
_create_index(const char* index_name,
size_t index_name_len,
Expand All @@ -141,7 +144,7 @@ static void stdb_create_index(MonoString* index_name_,
check_result(result);
}

__attribute__((import_module("spacetime"),
__attribute__((import_module(STDB_IMPORT_MODULE),
import_name("_iter_by_col_eq"))) extern uint16_t
_iter_by_col_eq(uint32_t table_id,
uint32_t col_id,
Expand All @@ -163,7 +166,7 @@ static MonoArray* stdb_iter_by_col_eq(uint32_t table_id,
return stdb_buffer_consume(out);
}

__attribute__((import_module("spacetime"),
__attribute__((import_module(STDB_IMPORT_MODULE),
import_name("_insert"))) extern uint16_t
_insert(uint32_t table_id, uint8_t* row, size_t row_len);

Expand All @@ -175,7 +178,7 @@ static void stdb_insert(uint32_t table_id, MonoArray* row_) {
check_result(result);
}

// __attribute__((import_module("spacetime"),
// __attribute__((import_module(STDB_IMPORT_MODULE),
// import_name("_delete_pk"))) extern uint16_t
// _delete_pk(uint32_t table_id, const uint8_t* pk, size_t pk_len);

Expand All @@ -187,7 +190,7 @@ static void stdb_insert(uint32_t table_id, MonoArray* row_) {
// check_result(result);
// }

// __attribute__((import_module("spacetime"),
// __attribute__((import_module(STDB_IMPORT_MODULE),
// import_name("_delete_value"))) extern uint16_t
// _delete_value(uint32_t table_id, const uint8_t* row, size_t row_len);

Expand All @@ -199,7 +202,7 @@ static void stdb_insert(uint32_t table_id, MonoArray* row_) {
// check_result(result);
// }

__attribute__((import_module("spacetime"),
__attribute__((import_module(STDB_IMPORT_MODULE),
import_name("_delete_by_col_eq"))) extern uint16_t
_delete_by_col_eq(uint32_t table_id,
uint32_t col_id,
Expand All @@ -221,7 +224,7 @@ static uint32_t stdb_delete_by_col_eq(uint32_t table_id,
return out;
}

// __attribute__((import_module("spacetime"),
// __attribute__((import_module(STDB_IMPORT_MODULE),
// import_name("_delete_range"))) extern uint16_t
// _delete_range(uint32_t table_id,
// uint32_t col_id,
Expand All @@ -248,7 +251,7 @@ static uint32_t stdb_delete_by_col_eq(uint32_t table_id,
// return out;
// }

__attribute__((import_module("spacetime"),
__attribute__((import_module(STDB_IMPORT_MODULE),
import_name("_iter_start"))) extern uint16_t
_iter_start(uint32_t table_id, BufferIter* out);

Expand All @@ -258,7 +261,7 @@ static void stdb_iter_start(uint32_t table_id, BufferIter* iter) {
check_result(result);
}

__attribute__((import_module("spacetime"),
__attribute__((import_module(STDB_IMPORT_MODULE),
import_name("_iter_start_filtered"))) extern uint16_t
_iter_start_filtered(uint32_t table_id,
const uint8_t* filter,
Expand All @@ -276,7 +279,7 @@ static void stdb_iter_start_filtered(uint32_t table_id,
check_result(result);
}

__attribute__((import_module("spacetime"),
__attribute__((import_module(STDB_IMPORT_MODULE),
import_name("_iter_next"))) extern uint16_t
_iter_next(BufferIter iter, Buffer* out);

Expand All @@ -289,7 +292,7 @@ static MonoArray* stdb_iter_next(BufferIter iter) {
return stdb_buffer_consume(out);
}

__attribute__((import_module("spacetime"),
__attribute__((import_module(STDB_IMPORT_MODULE),
import_name("_iter_drop"))) extern uint16_t
_iter_drop(BufferIter iter);

Expand All @@ -307,7 +310,7 @@ static void stdb_iter_drop(BufferIter* iter) {
check_result(result);
}

__attribute__((import_module("spacetime"),
__attribute__((import_module(STDB_IMPORT_MODULE),
import_name("_console_log"))) extern void
_console_log(uint8_t level,
const char* target,
Expand Down Expand Up @@ -335,7 +338,7 @@ static void stdb_console_log(MonoString* text_,
free_string(filename);
}

__attribute__((import_module("spacetime"),
__attribute__((import_module(STDB_IMPORT_MODULE),
import_name("_schedule_reducer"))) extern void
_schedule_reducer(const char* name,
size_t name_len,
Expand All @@ -360,19 +363,19 @@ static void stdb_schedule_reducer(
free_string(name);
}

__attribute__((import_module("spacetime"),
__attribute__((import_module(STDB_IMPORT_MODULE),
import_name("_cancel_reducer"))) extern void
_cancel_reducer(ScheduleToken token);

static void stdb_cancel_reducer(ScheduleToken* token) {
_cancel_reducer(*token);
}

__attribute__((import_module("spacetime"),
__attribute__((import_module(STDB_IMPORT_MODULE),
import_name("_buffer_len"))) extern size_t
_buffer_len(Buffer buf);

__attribute__((import_module("spacetime"),
__attribute__((import_module(STDB_IMPORT_MODULE),
import_name("_buffer_consume"))) extern void
_buffer_consume(Buffer buf, uint8_t* into, size_t len);

Expand All @@ -387,7 +390,7 @@ static MonoArray* stdb_buffer_consume(Buffer buf) {
return result;
}

__attribute__((import_module("spacetime"),
__attribute__((import_module(STDB_IMPORT_MODULE),
import_name("_buffer_alloc"))) extern Buffer
_buffer_alloc(const uint8_t* data, size_t data_len);

Expand Down Expand Up @@ -776,8 +779,3 @@ __attribute__((export_name("__preinit__10_init_csharp"))) void
__preinit__10_init_csharp() {
_start();
}

// __attribute__((export_name("SPACETIME_ABI_VERSION"))) -
// doesn't work on non-functions, must specify on command line
const uint32_t SPACETIME_ABI_VERSION = /* 5.0 */ (5 << 16) | 0;
const uint8_t SPACETIME_ABI_VERSION_IS_ADDR = 1;
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

<ItemGroup>
<WasiNativeFileReference Include="$(MSBuildThisFileDirectory)../bindings.c" />
<WasiNativeFileReference Include="-Wl,--export=SPACETIME_ABI_VERSION,--export=SPACETIME_ABI_VERSION_IS_ADDR" />
<WasiAfterRuntimeLoaded Include="mono_stdb_attach_bindings" />
</ItemGroup>

Expand Down
29 changes: 5 additions & 24 deletions crates/bindings-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,15 @@ use std::ptr;

use alloc::boxed::Box;

/// The current version of the ABI.
///
/// Exported as `SPACETIME_ABI_VERSION`, a `u32` WASM global.
/// If this global contains an address into linear memory at which the version is stored,
/// then a WASM global named `SPACETIME_ABI_VERSION_IS_ADDR` is also be exported.
///
/// In rust this looks like:
/// ```rust,ignore
/// #[no_mangle]
/// static SPACETIME_ABI_VERSION: u32 = _; // right now, rust `static`s always export as an address.
/// #[no_mangle]
/// static SPACETIME_ABI_VERSION_IS_ADDR: () = ();
/// ```
///
/// The (big-endian) first 2 bytes constitute the major version (`A`) of the ABI,
/// and the last 2 bytes constitute the minor version (`B`).
///
/// The semantics of a version number `A.B` is that a host implementing version `A.B`
/// can run a module declaring `X.Y` if and only if `X == A && Y <= B`.
/// So, the minor version is intended for backwards-compatible changes, e.g. adding a new function,
/// and the major version is for fully breaking changes.
pub const ABI_VERSION: u32 = 0x0005_0000;

/// Provides a raw set of sys calls which abstractions can be built atop of.
pub mod raw {
use core::mem::ManuallyDrop;

#[link(wasm_import_module = "spacetime")]
// this module identifier determines the abi version that modules built with this crate depend
// on. Any non-breaking additions to the abi surface should be put in a new `extern {}` block
// with a module identifier with a minor version 1 above the previous highest minor version.
// For breaking changes, all functions should be moved into one new `spacetime_X.0` block.
#[link(wasm_import_module = "spacetime_6.0")]
extern "C" {
/*
/// Create a table with `name`, a UTF-8 slice in WASM memory lasting `name_len` bytes,
Expand Down
8 changes: 0 additions & 8 deletions crates/bindings/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,6 @@ pub use log;

pub type Result<T = (), E = Errno> = core::result::Result<T, E>;

#[no_mangle]
static SPACETIME_ABI_VERSION: u32 = {
assert!(spacetimedb_lib::MODULE_ABI_VERSION.to_u32() == sys::ABI_VERSION);
sys::ABI_VERSION
};
#[no_mangle]
static SPACETIME_ABI_VERSION_IS_ADDR: () = ();

/// A context that any reducer is provided with.
#[non_exhaustive]
#[derive(Copy, Clone)]
Expand Down
20 changes: 6 additions & 14 deletions crates/cli/src/subcommands/generate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use clap::ArgAction::SetTrue;
use convert_case::{Case, Casing};
use duct::cmd;
use spacetimedb_lib::sats::{AlgebraicType, Typespace};
use spacetimedb_lib::{bsatn, MiscModuleExport, ModuleDef, ReducerDef, TableDef, TypeAlias};
use wasmtime::{AsContext, Caller, ExternType};
use spacetimedb_lib::{bsatn, MiscModuleExport, ModuleDef, ReducerDef, TableDef, TypeAlias, MODULE_ABI_MAJOR_VERSION};
use wasmtime::{AsContext, Caller};

mod code_indenter;
pub mod csharp;
Expand Down Expand Up @@ -343,18 +343,10 @@ fn extract_descriptions(wasm_file: &Path) -> anyhow::Result<ModuleDef> {
};
let mut store = wasmtime::Store::new(&engine, ctx);
let mut linker = wasmtime::Linker::new(&engine);
linker.allow_shadowing(true);
for imp in module.imports() {
if let ExternType::Func(func_type) = imp.ty() {
linker
.func_new(imp.module(), imp.name(), func_type, |_, _, _| {
anyhow::bail!("don't call me!!")
})
.unwrap();
}
}
linker.allow_shadowing(true).define_unknown_imports_as_traps(&module)?;
let module_name = &*format!("spacetime_{MODULE_ABI_MAJOR_VERSION}.0");
linker.func_wrap(
"spacetime",
module_name,
"_console_log",
|caller: Caller<'_, WasmCtx>,
_level: u32,
Expand All @@ -374,7 +366,7 @@ fn extract_descriptions(wasm_file: &Path) -> anyhow::Result<ModuleDef> {
}
},
)?;
linker.func_wrap("spacetime", "_buffer_alloc", WasmCtx::buffer_alloc)?;
linker.func_wrap(module_name, "_buffer_alloc", WasmCtx::buffer_alloc)?;
let instance = linker.instantiate(&mut store, &module)?;
let memory = Memory {
mem: instance.get_memory(&mut store, "memory").unwrap(),
Expand Down
5 changes: 2 additions & 3 deletions crates/core/src/host/wasm_common.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod abi;
pub mod module_host_actor;

use std::time::Instant;
Expand All @@ -17,9 +18,6 @@ pub const INIT_DUNDER: &str = "__init__";
/// the reducer with this name is invoked when updating the database
pub const UPDATE_DUNDER: &str = "__update__";

pub const STDB_ABI_SYM: &str = "SPACETIME_ABI_VERSION";
pub const STDB_ABI_IS_ADDR_SYM: &str = "SPACETIME_ABI_VERSION_IS_ADDR";

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[allow(unused)]
pub enum WasmType {
Expand Down Expand Up @@ -210,6 +208,7 @@ impl FuncNames {
pub enum ModuleCreationError {
WasmCompileError(anyhow::Error),
Init(#[from] module_host_actor::InitializationError),
Abi(#[from] abi::AbiVersionError),
}

pub trait ResourceIndex {
Expand Down
57 changes: 57 additions & 0 deletions crates/core/src/host/wasm_common/abi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
pub use spacetimedb_lib::VersionTuple;

const MODULE_PREFIX: &str = "spacetime_";

pub fn determine_spacetime_abi<I>(
imports: impl IntoIterator<Item = I>,
get_module: impl Fn(&I) -> &str,
) -> Result<Option<VersionTuple>, AbiVersionError> {
let it = imports.into_iter().filter_map(|imp| {
let s = get_module(&imp);
let err = || AbiVersionError::Parse { module: s.to_owned() };
s.strip_prefix(MODULE_PREFIX).map(|ver| {
let (major, minor) = ver.split_once('.').ok_or_else(err)?;
let (major, minor) = Option::zip(major.parse().ok(), minor.parse().ok()).ok_or_else(err)?;
Ok(VersionTuple { major, minor })
})
});
itertools::process_results(it, |mut it| try_reduce(&mut it, refine_ver_req))?
}

// TODO: replace with Iterator::try_reduce once stabilized
fn try_reduce<I: Iterator, E>(
it: &mut I,
f: impl FnMut(I::Item, I::Item) -> Result<I::Item, E>,
) -> Result<Option<I::Item>, E> {
let Some(first) = it.next() else { return Ok(None) };
it.try_fold(first, f).map(Some)
}

fn refine_ver_req(ver: VersionTuple, new: VersionTuple) -> Result<VersionTuple, AbiVersionError> {
if ver.major != new.major {
Err(AbiVersionError::MultipleMajor(ver.major, new.major))
} else {
Ok(Ord::max(ver, new))
}
}

pub fn verify_supported(implements: VersionTuple, got: VersionTuple) -> Result<(), AbiVersionError> {
if implements.supports(got) {
Ok(())
} else {
Err(AbiVersionError::UnsupportedVersion { implements, got })
}
}

#[derive(thiserror::Error, Debug)]
pub enum AbiVersionError {
#[error("import module {module:?} has malformed version string")]
Parse { module: String },
#[error("module cannot depend on both major version {0} and major version {1}")]
MultipleMajor(u16, u16),
#[error("abi version {got} is not supported (host implements {implements})")]
UnsupportedVersion {
got: VersionTuple,
implements: VersionTuple,
},
}
14 changes: 1 addition & 13 deletions crates/core/src/host/wasm_common/module_host_actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use bytes::Bytes;
use nonempty::NonEmpty;
use spacetimedb_lib::buffer::DecodeError;
use spacetimedb_lib::identity::AuthCtx;
use spacetimedb_lib::{bsatn, Address, IndexType, ModuleDef, VersionTuple};
use spacetimedb_lib::{bsatn, Address, IndexType, ModuleDef};
use spacetimedb_vm::expr::CrudExpr;

use crate::client::ClientConnectionSender;
Expand Down Expand Up @@ -91,20 +91,8 @@ pub(crate) struct WasmModuleHostActor<T: WasmModule> {
energy_monitor: Arc<dyn EnergyMonitor>,
}

#[derive(thiserror::Error, Debug)]
pub enum AbiVersionError {
#[error("module doesn't indicate spacetime ABI version")]
NoVersion,
#[error("abi version is malformed somehow (out-of-bounds, etc)")]
Malformed,
#[error("abi version {got} is not supported (host implements {implement})")]
UnsupportedVersion { got: VersionTuple, implement: VersionTuple },
}

#[derive(thiserror::Error, Debug)]
pub enum InitializationError {
#[error(transparent)]
Abi(#[from] AbiVersionError),
#[error(transparent)]
Validation(#[from] ValidationError),
#[error("setup function returned an error: {0}")]
Expand Down
Loading