Expand description
Piecrust VM for WASM smart contract execution.
A VM
is instantiated by calling VM::new
using a directory for
storage of commits.
Once instantiation has been successful, Session
s can be started using
VM::session
. A session represents the execution of a sequence of
call
and deploy
calls, and stores mutations to the underlying state
as a result. This sequence of mutations may be committed - meaning written
to the VM’s directory - using commit
. After a commit, the resulting
state may be used by starting a new session with it as a base.
Contract execution is metered in terms of gas
. The limit for gas used in a
call
or deploy
is passed in their respective function signatures. If the
limit is exceeded during the call an error will be returned. To learn more
about the compiler middleware used to achieve this, please refer to the
relevant runtime docs.
§State Representation and Session/Commit Mechanism
Smart Contracts are represented on disk by two separate files: their WASM bytecode and their linear memory at a given commit. The collection of all the memories of smart contracts at a given commit is referred to as the state of said commit.
During a session, each contract called in the sequence of queries/transactions is loaded by:
- Reading the contract’s bytecode file
- Memory mapping the linear memory file copy-on-write (CoW)
Using copy-on-write mappings of linear memories ensures that each commit is
never mutated in place by a session, with the important exception of
deletions
.
§Session Concurrency
Multiple sessions may be started concurrently on the same VM
, and then
passed on to different threads. These sessions are then non-overlapping
sequences of mutations of a state and may all be committed/dropped
simultaneously.
use piecrust::{Session, VM};
fn assert_send<T: Send>() {}
// Both VM and Session are `Send`
assert_send::<VM>();
assert_send::<Session>();
This is achieved by synchronizing commit deletions, and session spawns/commits using a synchronization loop started on VM instantiation.
§Call Atomicity
Contract calls are executed atomically, that is, they are either executed completely or they are not executed at all.
In other words, if the call succeeds, all the state mutations they produce are kept, while if they produce an error (e.g. they panic), all such mutations are reverted.
If the call was made within another call (i.e., the caller was a contract), we ensure all mutations are reverted by undoing the whole call stack of the current transact/query execution, and re-executing it with the exception of the error-producing call, which returns an error without being actually executed.
§32 vs 64-bit
Contracts can be compiled to either 32 or 64-bit WASM - i.e. the memory64
proposal. 32-bit contracts have a maximum memory size of 4GiB, while 64-bit
contracts have a maximum memory size of 4TiB.
§Usage
use piecrust::{contract_bytecode, ContractData, SessionData, VM};
let mut vm = VM::ephemeral().unwrap();
const OWNER: [u8; 32] = [0u8; 32];
const LIMIT: u64 = 1_000_000;
let mut session = vm.session(SessionData::builder()).unwrap();
let counter_id = session
.deploy(
contract_bytecode!("counter"),
ContractData::builder().owner(OWNER),
LIMIT,
)
.unwrap();
assert_eq!(session.call::<_, i64>(counter_id, "read_value", &(), LIMIT).unwrap().data, 0xfc);
session.call::<_, ()>(counter_id, "increment", &(), LIMIT).unwrap();
assert_eq!(session.call::<_, i64>(counter_id, "read_value", &(), LIMIT).unwrap().data, 0xfd);
let commit_root = session.commit().unwrap();
assert_eq!(commit_root, vm.commits()[0]);
Macros§
Structs§
- An archived
Event
- The tree of contract calls.
- An element of the call tree.
- ID to identify the wasm contracts after they have been deployed
- The resolver for an archived
ContractId
- And event emitted by a contract.
- The resolver for an archived
Event
- A Merkle opening for page in the state.
- A running mutation to a state.
- A handle to the piecrust virtual machine.
Enums§
- An archived
ContractError
- The error possibly returned on an inter-contract-call.
- The resolver for an archived
ContractError
- The error type returned by the piecrust VM.
Constants§
- The size of the argument buffer in bytes
- The length of
ContractId
in bytes - How many bytes to use for scratch space when serializing
Traits§
- A query executable on the host.
Type Aliases§
- Type with
rkyv
serialization capabilities for specific types.