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§
- Archived
Event - An archived
Event
- Call
Receipt - The receipt given for a call execution using one of either
call
orcall_raw
. - Call
Tree - The tree of contract calls.
- Call
Tree Elem - An element of the call tree.
- Contract
Data - Contract
Data Builder - Contract
Id - ID to identify the wasm contracts after they have been deployed
- Contract
IdResolver - The resolver for an archived
ContractId
- Event
- And event emitted by a contract.
- Event
Resolver - The resolver for an archived
Event
- Page
Opening - A Merkle opening for page in the state.
- Session
- A running mutation to a state.
- Session
Data - VM
- A handle to the piecrust virtual machine.
Enums§
- Archived
Contract Error - An archived
ContractError
- Contract
Error - The error possibly returned on an inter-contract-call.
- Contract
Error Resolver - The resolver for an archived
ContractError
- Error
- The error type returned by the piecrust VM.
Constants§
- ARGBUF_
LEN - The size of the argument buffer in bytes
- CONTRACT_
ID_ BYTES - The length of
ContractId
in bytes - SCRATCH_
BUF_ BYTES - How many bytes to use for scratch space when serializing
Traits§
- Host
Query - A query executable on the host.
Type Aliases§
- Standard
BufSerializer - Type with
rkyv
serialization capabilities for specific types.