Rust
This section explains step by step how to write a new smart contract on Casper. Start with main.rs from the previous section.
A Basic Smart Contract in Rust
The Casper VM executes a smart contract by calling the call function specified in the contract. If the function is missing, the smart contract is not valid. The simplest possible example is an empty call function.
#[no_mangle]
pub extern "C" fn call() {}
The #[no_mangle] attribute prevents the compiler from changing (mangling) the function name when converting to the binary format of Wasm. Without it, the VM exits with the error message: Module doesn't have export call.
Arguments
It's possible to pass arguments to smart contracts. To leverage this feature, use runtime::get_named_arg.
use casperlabs_contract::contract_api::runtime;
#[no_mangle]
pub extern "C" fn call() {
let value: String = runtime::get_named_arg("value");
}
Storage
Saving and reading values to and from the blockchain is a manual process in Casper. It requires more code to be written, but also provides a lot of flexibility. The storage system works similarly to a file system in an operating system. Let's say we have a string "Hello Casper!" that needs to be saved. To do this, use the text editor, create a new file, paste the string in and save it under a name in some directory. The pattern is similar on the Casper blockchain. First you have to save your value to the memory using storage::new_uref. This returns a reference to the memory object that holds the "Hello Casper!" value. You could use this reference to update the value to something else. It's like a file. Secondly you have to save the reference under a human-readable string using runtime::put_key. It's like giving a name to the file. The following function implements this scenario:
const KEY: &str = "special_value";
fn store(value: String) {
// Store `value` under a new unforgeable reference.
let value_ref = storage::new_uref(value);
// Wrap the unforgeable reference in a `Key`.
let value_key: Key = value_ref.into();
// Store this key under the name "special_value" in context-local storage.
runtime::put_key(KEY, value_key);
}
After this function is executed, the context (Account or Smart Contract) will have the content of the value stored under KEY in its named keys space. The named keys space is a key-value storage that every context has. It's like a home directory.
Final Smart Contract
The code below is the simple contract generated by cargo-casper (found in contract/src/main.rs of a project created by the tool). It reads an argument and stores it in the memory under a key named "special_value".
#![cfg_attr(
not(target_arch = "wasm32"),
crate_type = "target arch should be wasm32"
)]
#![no_main]
use casperlabs_contract::{
contract_api::{runtime, storage},
};
use casperlabs_types::{Key, URef};
const KEY: &str = "special_value";
const ARG_MESSAGE: &str = "message";
fn store(value: String) {
// Store `value` under a new unforgeable reference.
let value_ref: URef = storage::new_uref(value);
// Wrap the unforgeable reference in a value of type `Key`.
let value_key: Key = value_ref.into();
// Store this key under the name "special_value" in context-local storage.
runtime::put_key(KEY, value_key);
}
// All session code must have a `call` entrypoint.
#[no_mangle]
pub extern "C" fn call() {
// Get the optional first argument supplied to the argument.
let value: String = runtime::get_named_arg(ARG_MESSAGE);
store(value);
}
Using Error Codes
The Casper VM supports error codes in smart contracts. A contract can stop execution and exit with a given error via the runtime::revert function:
use casperlabs_contract::contract_api::runtime;
use casperlabs_types::ApiError;
#[no_mangle]
pub extern "C" fn call() {
runtime::revert(ApiError::PermissionDenied)
}
When a contract exits with an error code, the exit code is visible in the Block Explorer.
Tests
Refer to the Testing Contract section to view more details about the smart contract testing procedure.
WASM File Size
We encourage shrinking the WASM file size as much as possible. Smaller deploys cost less and save the network bandwidth. We recommend reading Shrinking .wasm Code Size chapter of The Rust Wasm Book.