Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Jade Framework

Jade is a development framework for building polkadot JAM services developed by SpaceJam.

Installation

cargo install jade

Quick Start

jade new my-service
cd my-service
cargo nextest run

Service Structure

Jade currently supports two types of services: authorizer service and general service, there is also corevm service supported in our toolkit but it has not been official integrated in JAM implementations yet.

  • [no_std]: we need to avoid standard rust library on building riscv64 services for making our compiled binaries compatible with the JAM virtual machines.
  • #[jade::is_authorized]: the entrypoint of the is_authorized logic.
  • #[jade::refine]: the entrypoint of the refine logic.
  • #[jade::accumulate]: the entrypoint of the accumulate logic.

Note that authorizer service and general service are different service types, you cannot declare both #[jade::is_authorized] and #[jade::refine] (or #[jade::accumulate]) in the same service.

Authorizer Service

#![allow(unused)]
#![cfg_attr(target_arch = "riscv64", no_std)]
fn main() {
use jade::prelude::{AuthTrace, CoreIndex};

#[jade::is_authorized]
fn is_authorized(_core_index: CoreIndex) -> AuthTrace {
    Default::default()
}
}

General Service

#![allow(unused)]
#![cfg_attr(target_arch = "riscv64", no_std)]
fn main() {
use jade::prelude::{AuthTrace, CoreIndex};

#[jade::refine]
fn refine(
    core: u16,
    index: u16,
    id: u32,
    payload: Vec<u8>,
    package_hash: OpaqueHash,
) -> Vec<u8> {
    // ... refine logic here
}

#[jade::accumulate]
fn accumulate(now: u32, id: u32, results: Vec<Operand>) -> Option<OpaqueHash> {
    // ... accumulate logic here
}
}

Build Service

There are two ways to build a service: using jade command line tool or using rust build script.

Using jade command line tool

cargo install jade
cd my-service
jade build

Using rust build script

# my-service/Cargo.toml
#
# ...
#
[build-dependencies]
cjam = "*"
// my-service/build.rs

fn main() {
    cjam::util::build(
        env!("CARGO_PKG_NAME"),
        // or Some(cjam::ModuleType::Authorizer)
        Some(cjam::ModuleType::Service),
    ).ok();
}

Service Testing

Jade provides a testing module for testing your service.

#![allow(unused)]
fn main() {
//! stoken/tests/main.rs
use jade::testing::Jam;
use stoken::{Holders, Instruction, SERVICE};

const AUTHORIZER_ID: u32 = 500;
const SERVICE_ID: u32 = 501;
const ALICE: u32 = 0;

#[test]
fn test_mint() {
    // initialize the logger
    jade::testing::util::init_logger();

    // Set up JAM with authorization using the null authorizer service
    let mut jam = Jam::default().with_auth(AUTHORIZER_ID, nauth::SERVICE.to_vec());
    jam.add_service(SERVICE_ID, SERVICE.to_vec());

    // 1. send a mint instruction
    let amount = 100;
    let instr = vec![Instruction::Mint { to: ALICE, amount }];
    let info = jam
        .execute(SERVICE_ID, codec::encode(&instr).unwrap())
        .expect("failed to execute work item");

    // 2. check the balance
    let holders: Holders = info
        .get_storage(SERVICE_ID, Holders::key())
        .expect("failed to get holders");
    assert_eq!(holders.balance(ALICE), amount);
}
}