2 releases
| 0.1.1 | Dec 29, 2025 |
|---|---|
| 0.1.0 | Dec 29, 2025 |
#285 in Cargo plugins
120KB
2.5K
SLoC
cargo-polkajam
cargo, make me a JAM service
A Rust cargo subcommand for generating and building JAM (Join-Accumulate Machine) services for Polkadot. Follows the cargo-generate project architecture while providing JAM-specific tooling.
Demo
Installation
Install From crates.io
cargo install cargo-polkajam
Install From source
git clone https://github.com/abutlabs/cargo-polkajam
cd cargo-polkajam
cargo install --path .
To reinstall after making changes:
cargo install --path . --force
Prerequisites
Before using cargo-polkajam, you need:
- Rust toolchain with nightly support
- jam-pvm-build - PVM bytecode compiler
cargo install jam-pvm-build
Quick Start
# 1. Install the JAM toolchain (downloads polkajam binaries)
cargo polkajam setup
# 2. Create a new JAM service
cargo polkajam new my-service
# 3. Build the service
cd my-service
cargo polkajam build
# 4. Start local testnet
cargo polkajam up
# 5. Deploy to testnet (in another terminal)
cargo polkajam deploy my-service.jam
# 6. Stop testnet when done
cargo polkajam down
Commands
cargo polkajam setup
Downloads and installs the JAM/polkajam toolchain from polkajam-releases.
# Install latest nightly
cargo polkajam setup
# List available versions
cargo polkajam setup --list
# Show installed toolchain info
cargo polkajam setup --info
# Install specific version
cargo polkajam setup --version nightly-2025-12-29
# Force reinstall
cargo polkajam setup --force
# Update to latest
cargo polkajam setup --update
Installed binaries (in ~/.cargo-polkajam/toolchain/polkajam-nightly/):
polkajam- JAM nodejamt- JAM CLI tool for deploymentpolkajam-testnet- Local testnet runnerpolkajam-repl- Interactive REPLcorevm-builder- CoreVM builder- And more...
cargo polkajam new
Creates a new JAM service project from a template.
# Interactive mode
cargo polkajam new my-service
# Skip prompts, use defaults
cargo polkajam new my-service --defaults
# Use custom git template
cargo polkajam new my-service --git https://github.com/user/template
# Specify template values
cargo polkajam new my-service -d author="Your Name" -d license=MIT
Options:
-t, --template <name>- Template name (default: basic-service)--git <url>- Git repository URL for custom template--branch <branch>- Git branch (requires --git)--path <path>- Subdirectory in git repo (requires --git)-o, --output <dir>- Output directory--defaults- Skip prompts, use defaults-d, --define <key=value>- Set template variable--no-git- Don't initialize git repository
cargo polkajam build
Builds a JAM service into a .jam blob using jam-pvm-build.
# Build in release mode (default)
cargo polkajam build
# Build specific project
cargo polkajam build --path /path/to/service
# Custom output path
cargo polkajam build --output my-service.jam
# Verbose output
cargo polkajam build --verbose
Options:
-p, --path <dir>- Project path (default: current directory)--release- Build in release mode (default: true)-o, --output <path>- Output path for .jam blob-v, --verbose- Verbose output
cargo polkajam up
Starts the local JAM testnet.
# Start in background (default)
cargo polkajam up
# Start in foreground (see logs)
cargo polkajam up --foreground
# Custom RPC endpoint
cargo polkajam up --rpc ws://localhost:9944
Options:
--foreground- Run in foreground (see logs, Ctrl+C to stop)--rpc <url>- RPC endpoint (default: ws://localhost:19800)-v, --verbose- Verbose output
cargo polkajam down
Stops the local JAM testnet.
# Stop the testnet gracefully
cargo polkajam down
# Force kill
cargo polkajam down --force
Options:
--force- Force kill with SIGKILL instead of SIGTERM-v, --verbose- Verbose output
cargo polkajam deploy
Deploys a JAM service to the network.
# Deploy a service
cargo polkajam deploy my-service.jam
# Deploy with initial balance
cargo polkajam deploy my-service.jam --amount 1000
# Deploy with memo
cargo polkajam deploy my-service.jam --memo "my memo data"
# Deploy to custom RPC endpoint
cargo polkajam deploy my-service.jam --rpc ws://localhost:9944
# Register service with a name
cargo polkajam deploy my-service.jam --register my_service
Options:
--amount <value>- Initial balance for the service (default: 0)--memo <data>- Memo data to include-G, --min-item-gas <value>- Minimum gas per work item (default: 1000000)-g, --min-memo-gas <value>- Minimum gas for memo (default: 1000000)-r, --register <name>- Register service with a name--rpc <url>- RPC endpoint (default: ws://localhost:19800)-v, --verbose- Verbose output
cargo polkajam monitor
Monitor the testnet with an interactive TUI (jamtop).
# Start the monitor
cargo polkajam monitor
# Monitor with custom RPC endpoint
cargo polkajam monitor --rpc ws://localhost:9944
Options:
--rpc <url>- RPC endpoint (default: ws://localhost:19800)-v, --verbose- Verbose output
cargo polkajam test
Run comprehensive end-to-end tests that verify the entire workflow.
# Run full test suite
cargo polkajam test
# Run tests with verbose output
cargo polkajam test --verbose
# Keep testnet running after tests (for debugging)
cargo polkajam test --keep-running
# Skip testnet startup (use already running testnet)
cargo polkajam test --skip-testnet
# Use custom test directory
cargo polkajam test --dir /tmp/my-test
Options:
--keep-running- Keep testnet running after tests complete--skip-testnet- Skip testnet startup (assume already running)--dir <path>- Test directory (default: temp directory)-v, --verbose- Verbose output with command details
Tests performed:
- Create new JAM service (
cargo polkajam new) - Build JAM service to
.jamblob (cargo polkajam build) - Deploy to local testnet (start → deploy → stop)
Local Development
Running from source
# Run commands directly
cargo run -- setup --info
cargo run -- new test-service --defaults
cargo run -- build
# Or build and install locally
cargo build && cargo install --path . --force
Development workflow
# Make changes, rebuild, and test
cargo build && cargo install --path . --force && cargo polkajam setup --info
Uninstall
cargo uninstall cargo-polkajam
rm -rf ~/.cargo-polkajam # Remove toolchain and config
Testing with Local Testnet
Full end-to-end test
# Terminal 1: Start the testnet
cargo polkajam up --foreground
# Terminal 2: Create and deploy a service
cargo polkajam new test-service --defaults
cd test-service
cargo polkajam build
cargo polkajam deploy test-service.jam
# Stop the testnet when done
cargo polkajam down
Background mode workflow
# Start testnet in background
cargo polkajam up
# Create, build, and deploy
cargo polkajam new test-service --defaults
cd test-service
cargo polkajam build
cargo polkajam deploy test-service.jam
# Stop testnet
cargo polkajam down
Additional testnet tools
# Monitor with jamtop
cargo polkajam monitor
# Interactive REPL
~/.cargo-polkajam/toolchain/polkajam-nightly/polkajam-repl
Project Structure
Generated JAM service structure:
my-service/
├── Cargo.toml # Dependencies: jam-pvm-common, polkavm-derive
├── src/
│ └── lib.rs # Service implementation (refine, accumulate)
└── .gitignore
Service Implementation
#![no_std]
#![no_main]
extern crate alloc;
use jam_pvm_common::{declare_service, Service, accumulate::*, jam_types::*};
declare_service!(MyService);
struct MyService;
impl Service for MyService {
fn refine(
_core_index: CoreIndex,
_item_index: usize,
_service_id: ServiceId,
payload: WorkPayload,
_package_hash: WorkPackageHash,
) -> WorkOutput {
// Stateless computation (up to 6 seconds)
payload.take().into()
}
fn accumulate(
_slot: Slot,
_service_id: ServiceId,
item_count: usize,
) -> Option<Hash> {
// Stateful integration (~10ms)
None
}
}
Configuration
Configuration is stored in ~/.cargo-polkajam/:
~/.cargo-polkajam/
├── config.toml # Toolchain configuration
└── toolchain/
└── polkajam-nightly/ # Installed binaries
config.toml:
installed_version = "nightly-2025-12-29"
toolchain_path = "/Users/you/.cargo-polkajam/toolchain"
installed_at = "1767015039"
Running Tests
End-to-end tests (recommended)
The easiest way to test the entire cargo-polkajam workflow:
# Run full end-to-end test suite
cargo polkajam test
# Run with verbose output
cargo polkajam test --verbose
This automatically tests: new → build → up → deploy → down
Unit and integration tests
# Run all Rust tests (excluding ignored tests)
cargo test
# Run with verbose output
cargo test -- --nocapture
Full integration tests (require jam-pvm-build)
# Run ignored tests that require toolchain
cargo test --test integration_tests -- --ignored
Manual testnet deployment tests
These tests require a running local testnet:
# Terminal 1: Start the testnet
cargo polkajam up --foreground
# Terminal 2: Run testnet tests
cargo test --test testnet_tests -- --ignored --nocapture
The testnet tests will:
- Create a new JAM service
- Build it to a
.jamblob - Deploy it to the running testnet using
cargo polkajam deploy
Publishing & Releases
Automated Releases (Recommended)
This repo has CI/CD that automatically publishes to crates.io when you create a version tag:
One-time setup:
- Get your crates.io API token from https://crates.io/settings/tokens
- Add it as a GitHub secret: Settings → Secrets → Actions → New secret
- Name:
CARGO_REGISTRY_TOKEN - Value: your token
- Name:
To release a new version:
# Update version in Cargo.toml
# Commit changes
git add . && git commit -m "Release v0.1.0"
# Create and push a version tag
git tag v0.1.0
git push origin main --tags
This triggers the release workflow which:
- Runs all tests and lints
- Publishes to crates.io
- Builds binaries for Linux and macOS
- Creates a GitHub Release with downloadable binaries
Manual Publishing
# Login to crates.io
cargo login <your-token>
# Dry run to verify
cargo publish --dry-run
# Publish
cargo publish
Reference JAM Service implementations
- zk-jam-service - Zero-knowledge proof verification service
Resources
- JAM Gray Paper - Official JAM specification
- PolkaVM - The virtual machine powering JAM
- polkajam-releases - JAM toolchain releases
- Building JAM Services in Rust - Forum discussion
License
MIT OR Apache-2.0
Dependencies
~31–51MB
~858K SLoC