jam_pvm_common/
lib.rs

1//! The main JAM PVM API for creating authorizers and services on JAM. This includes a trait-based
2//! invocation entry-point API as well as host-calls functions and types for working with them.
3//!
4//! In order to create a PVM executable containing a JAM service or authorizer, you must implement
5//! the [Service] or [Authorizer] in some type and then pass your type into the `declare_service!`
6//! or `declare_authorizer!` macro, respectively. This will generate the necessary entry-points for
7//! the PVM to call into your implementation.
8//!
9//! ## Example Service
10#![cfg_attr(feature = "service", doc = "```rust")]
11#![cfg_attr(not(feature = "service"), doc = "```ignore")]
12//! extern crate alloc;
13//! use alloc::vec::Vec;
14//! use jam_pvm_common::{declare_service, Service, accumulate::{set_storage, accumulate_items}};
15//! use jam_types::*;
16//!
17//! struct MyService;
18//! declare_service!(MyService);
19//!
20//! impl Service for MyService {
21//!     fn refine(
22//!         _core_index: CoreIndex,
23//!         _item_index: usize,
24//!         _service_id: ServiceId,
25//!         payload: WorkPayload,
26//!         _package_hash: WorkPackageHash,
27//!     ) -> WorkOutput {
28//!         [&b"Hello "[..], payload.take().as_slice()].concat().into()
29//!     }
30//!     fn accumulate(_slot: Slot, _service_id: ServiceId, _item_count: usize) -> Option<Hash> {
31//!         for item in accumulate_items().into_iter() {
32//!             match item {
33//!                 AccumulateItem::WorkItem(w) => {
34//!                     if let Ok(data) = w.result {
35//!                         set_storage(w.package.as_slice(), &data).expect("not enough balance?!");
36//!                     }
37//!                 },
38//!                 AccumulateItem::Transfer(t) => {
39//!                     // ...
40//!                 }
41//!             }
42//!         }
43//!         None
44//!     }
45//! }
46//! ```
47//! 
48//! ## Host-calls
49//! The host-calls available to a service or authorizer are split into three modules:
50//! - [is_authorized] for authorizers, to be called from the [Authorizer::is_authorized] function.
51//! - [refine] for services, to be called from the [Service::refine] function.
52//! - [accumulate] for services, to be called from the [Service::accumulate] function.
53//!
54//! Each module contains a set of functions that can be called from the respective entry-point
55//! function. These functions are used to interact with the PVM and the blockchain state.
56//!
57//! ## Logging
58//! Five logging macros are provided similar to those of the `log` crate, [debug], [info], [warn],
59//! [error], and [trace]. These macros are used with the non-standard PolkaJam `log` host-call and
60//! the `format` macro. The host environment is responsible for forwarding these logs to the
61//! appropriate destination.
62//!
63//! ## Features
64//! - `authorizer`: Enables the authorizer API.
65//! - `service`: Enables the service API.
66//! - `logging`: Enables the logging service; without the logging macros will evaluate any operands
67//!   but otherwise have no effect.
68#![no_std]
69#![allow(clippy::unwrap_used)]
70#![allow(unexpected_cfgs)] // To prevent warnings about `target_env = "polkavm"`.
71
72extern crate alloc;
73
74#[doc(hidden)]
75pub use jam_types;
76
77#[cfg(any(feature = "authorizer", doc))]
78mod authorizer;
79#[cfg(any(feature = "authorizer", doc))]
80pub use authorizer::Authorizer;
81
82#[cfg(any(feature = "service", doc))]
83mod service;
84#[cfg(any(feature = "service", doc))]
85pub use service::Service;
86
87#[allow(dead_code)]
88mod host_calls;
89
90#[cfg(target_env = "polkavm")]
91mod panic_handler;
92#[cfg(any(feature = "service", feature = "authorizer", doc))]
93pub mod startup;
94
95/// Host-call APIs available for the [Authorizer::is_authorized] entry-point.
96#[cfg(any(feature = "authorizer", doc))]
97pub mod is_authorized {
98	pub use super::host_calls::{
99		fetch_wrappers::{
100			auth_token, authorizer, protocol_parameters, refine_context, work_item_payload,
101			work_item_summary, work_items_summary, work_package,
102		},
103		gas,
104	};
105}
106
107/// Host-call APIs available for the [Service::refine] entry-point.
108#[cfg(any(feature = "service", doc))]
109pub mod refine {
110	pub use super::host_calls::{
111		export, export_slice, expunge,
112		fetch_wrappers::{
113			any_extrinsic, any_import, auth_token, auth_trace, authorizer, entropy, extrinsic,
114			extrinsic_slice, import, protocol_parameters, refine_context, work_item_payload,
115			work_item_summary, work_items_summary, work_package,
116		},
117		foreign_historical_lookup as foreign_lookup,
118		foreign_historical_lookup_into as foreign_lookup_into, gas, historical_lookup as lookup,
119		historical_lookup_into as lookup_into, invoke,
120		is_foreign_historical_available as is_foreign_available,
121		is_historical_available as is_available, machine, peek, peek_into, peek_value, poke,
122		poke_value, void, zero,
123	};
124}
125
126/// Host-call APIs available for the [Service::accumulate] entry-point.
127#[cfg(any(feature = "service", doc))]
128pub mod accumulate {
129	pub use super::host_calls::{
130		assign, bless, checkpoint, create_service, create_service_ext, designate, eject,
131		fetch_wrappers::{accumulate_item, accumulate_items, entropy, protocol_parameters},
132		foreign_lookup, foreign_lookup_into, forget, gas, get, get_foreign, get_foreign_storage,
133		get_storage, is_available, is_foreign_available, lookup, lookup_into, my_info, provide,
134		query, remove, remove_storage, service_info, set, set_storage, solicit, transfer, upgrade,
135		yield_hash, zombify, ForgetImplication, LookupRequestStatus,
136	};
137}
138
139#[cfg(feature = "service")]
140#[doc(hidden)]
141pub mod internal {
142	pub use super::host_calls::raw_service_info_field;
143}
144
145#[doc(hidden)]
146pub mod imports;
147
148#[doc(hidden)]
149pub mod logging;
150
151#[doc(hidden)]
152pub mod mem;
153
154mod result;
155pub use result::{ApiError, ApiResult, InvokeOutcome, InvokeResult};