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
242 changes: 238 additions & 4 deletions Cargo.lock

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ repository = "https://github.com/spacejamapp/jade"
cjam = { path = "crates/cli" }
jade = { path = "crates/jade", default-features = false }
jade-derive = { path = "crates/jade/derive" }
sys = { path = "crates/sys" }
spacevm = { path = "crates/sys", package = "spacevm-sys" }
testing = { path = "crates/testing", package = "jade-testing" }

# services
nauth = { path = "services/nauth" }
stoken = { path = "services/stoken" }

# spacejam dependencies
codec = { package = "serde-jam", version = "0.0.13-pre.1", default-features = false }
Expand Down
13 changes: 8 additions & 5 deletions crates/cli/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ pub fn build_pvm_blob(
}

child
.args(["build", "-Z", "build-std=core,alloc"])
.args(["rustc", "-Z", "build-std=core,alloc"])
.arg(profile.to_arg())
.arg("--target")
.arg(target_json_path)
Expand All @@ -170,7 +170,9 @@ pub fn build_pvm_blob(
"tiny"
} else {
""
}) // Disable stripping for LLVM 19 compatibility
})
.arg("--lib")
.arg("--crate-type=cdylib")
.env(
"RUSTFLAGS",
format!(
Expand Down Expand Up @@ -223,12 +225,13 @@ pub fn build_pvm_blob(
.expect("Failed to link pvm program:");

// Write out a full `.pvm` blob for debugging/inspection.
fs::create_dir_all(out_dir).expect("Failed to create jam directory");
let output_path_pvm = out_dir.join(format!("{}.pvm", &info.name));
let jam_out = out_dir.join("jam");
fs::create_dir_all(&jam_out).expect("Failed to create jam directory");
let output_path_pvm = jam_out.join(format!("{}.pvm", &info.name));
fs::write(output_path_pvm, &linked).expect("Error writing resulting binary");
let name = info.name.clone();
let metadata = ConventionalMetadata::Info(info).encode().into();
let output_file = blob_type.output_file(out_dir, &name);
let output_file = blob_type.output_file(&jam_out, &name);
if !matches!(blob_type, BlobType::CoreVmGuest) {
let parts = polkavm_linker::ProgramParts::from_bytes(linked.into())
.expect("failed to deserialize linked PolkaVM program");
Expand Down
3 changes: 1 addition & 2 deletions crates/cli/src/cmd/build.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
//! `jam build` command

use std::path::PathBuf;

use crate::{
builder,
manifest::{ModuleType, Profile},
};
use clap::Parser;
use std::path::PathBuf;

/// CLI utility for building PVM code blobs, particularly services and authorizers.
#[derive(Parser, Debug, Default)]
Expand Down
5 changes: 2 additions & 3 deletions crates/cli/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@ pub fn build(package: &str, module: Option<ModuleType>, path: Option<String>) ->

// Build the service
let target = etc::find_up("target")?;
let jam = target.join("jam");
let current = path
.map(PathBuf::from)
.unwrap_or_else(|| env::current_dir().expect("Unable to get current directory"));
let binary = jam.join(package).join(format!("{package}.jam"));
let binary = target.join("jam").join(format!("{package}.jam"));
let rebuild = if !binary.exists() {
true
} else {
Expand All @@ -36,7 +35,7 @@ pub fn build(package: &str, module: Option<ModuleType>, path: Option<String>) ->
if let Some(module) = module {
build.module = module;
}
build.target = Some(jam.join(package));
build.target = Some(target);
build.run()?;
}

Expand Down
7 changes: 6 additions & 1 deletion crates/jade/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,17 @@ homepage.workspace = true
repository.workspace = true

[dependencies]
anyhow.workspace = true
codec.workspace = true
jade-derive.workspace = true
serde.workspace = true
service.workspace = true
polkavm-derive.workspace = true
testing = { workspace = true, optional = true }

[features]
default = []
std = ["codec/std", "service/std"]
logging = []
testing = ["dep:testing"]
std = ["anyhow/std", "codec/std", "serde/std", "service/std"]
tiny = []
3 changes: 2 additions & 1 deletion crates/jade/derive/src/accumulate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ pub fn accumulate(_args: TokenStream, input: TokenStream) -> TokenStream {
let buf = unsafe { core::slice::from_raw_parts(ptr as *const u8, size as usize) };
let jade::service::vm::AccumulateParams {slot, id, results} =
jade::codec::decode(buf).expect("failed to decode accumulate parameters");
if let Some(result) = #funame(slot, id, results) {
let operands = jade::host::fetch::operands().expect("failed to fetch operands");
if let Some(result) = #funame(slot, id, operands) {
((&result).as_ptr() as u64, result.len() as u64)
} else {
(0, 0)
Expand Down
7 changes: 4 additions & 3 deletions crates/jade/derive/src/authorize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ pub fn is_authorized(_args: TokenStream, input: TokenStream) -> TokenStream {
#fun

let buf = unsafe { core::slice::from_raw_parts(ptr as *const u8, size as usize) };
let (param, package, core_index): (AuthConfig, WorkPackage, CoreIndex) =
jade::codec::decode(buf).expect("failed to decode is_authorized parameters");
let result = #funame(param, package, core_index);
let core_index: CoreIndex =
jade::codec::decode(buf).inspect_err(|e| jade::error!("decoded is_authorized parameters: {:?}", e))
.expect("failed to decode is_authorized parameters");
let result = #funame(core_index);
((&result).as_ptr() as u64, result.len() as u64)
}
}
Expand Down
80 changes: 80 additions & 0 deletions crates/jade/src/host/general.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
//! General host calls

use crate::host::import;
use core::ptr;

/// Get the gas used
pub fn gas() -> u64 {
unsafe { import::gas() }
}

/// Fetch operations
pub mod fetch {
use super::*;
use crate::prelude::{Vec, vec};
use anyhow::Result;
use service::vm::Operand;

/// Fetch a value from the storage
pub fn operands() -> Result<Vec<Operand>> {
let len = unsafe { import::fetch(core::ptr::null_mut(), 0, 0, 14, 0, 0) };
let mut target = vec![0; len as usize];
let _ = unsafe { import::fetch(target.as_mut_ptr(), 0, len as u64, 14, 0, 0) };
codec::decode(target.as_slice()).map_err(Into::into)
}
}

/// Storage operations
pub mod storage {
use super::*;
use anyhow::Result;

/// Read a value from the storage
pub fn read<R: serde::de::DeserializeOwned>(key: impl AsRef<[u8]>) -> Option<R> {
let len = unsafe {
import::read(
u64::MAX as _,
key.as_ref().as_ptr(),
key.as_ref().len() as u64,
ptr::null_mut(),
0,
0,
)
};

if len == u64::MAX {
return None;
} else if len == 0 {
return None;
}

let ptr = unsafe {
import::read(
u64::MAX as _,
key.as_ref().as_ptr(),
key.as_ref().len() as u64,
ptr::null_mut(),
0,
len,
)
};

let value = unsafe { core::slice::from_raw_parts(ptr as _, len as usize) };
codec::decode(value).ok()
}

/// Write a value to the storage
pub fn write<W: serde::Serialize>(key: impl AsRef<[u8]>, value: &W) -> Result<()> {
let value = codec::encode(value)?;
unsafe {
import::write(
key.as_ref().as_ptr(),
key.as_ref().len() as u64,
value.as_ptr(),
value.len() as u64,
);
};

Ok(())
}
}
41 changes: 41 additions & 0 deletions crates/jade/src/host/import.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//! Imports of host calls

#[polkavm_derive::polkavm_import]
extern "C" {
// NOTE: This is NOT part of the GP.
#[polkavm_import(index = 100)]
pub fn log(
level: u64,
target_ptr: *const u8,
target_len: u64,
text_ptr: *const u8,
text_len: u64,
);

/// Get the gas used
#[polkavm_import(index = 0)]
pub fn gas() -> u64;

/// Fetch a value from the storage
#[polkavm_import(index = 1)]
pub fn fetch(buffer: *mut u8, offset: u64, buffer_len: u64, kind: u64, a: u64, b: u64) -> u64;

/// Read a value from the storage
#[polkavm_import(index = 3)]
pub fn read(
service: u64,
key_ptr: *const u8,
key_len: u64,
out: *mut u8,
offset: u64,
out_len: u64,
) -> u64;

/// Write a value to the storage
#[polkavm_import(index = 4)]
pub fn write(key_ptr: *const u8, key_len: u64, value: *const u8, value_len: u64) -> u64;

/// Get the info of the service
#[polkavm_import(index = 5)]
pub fn info(service: u64, service_info_ptr: *mut u8) -> u64;
}
6 changes: 6 additions & 0 deletions crates/jade/src/host/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//! Host calls

pub use general::*;

mod general;
pub(crate) mod import;
5 changes: 5 additions & 0 deletions crates/jade/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@ extern crate alloc;

pub use {codec, jade_derive::*, polkavm_derive, service};

pub mod host;
pub mod logging;
pub mod prelude;

#[cfg(feature = "testing")]
pub use testing;

#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
#[global_allocator]
static ALLOCATOR: polkavm_derive::LeakingAllocator = polkavm_derive::LeakingAllocator;
Expand Down
Loading